@alfe.ai/mcp-server 0.1.19 → 0.2.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.
package/dist/bin.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ const require_index = require("./index.cjs");
2
3
  //#region src/bin.ts
3
- require("./index.cjs").main();
4
+ require_index.main({ profile: require_index.parseProfileArg(process.argv.slice(2)) });
4
5
  //#endregion
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { main } from "./index.js";
2
+ import { main, parseProfileArg } from "./index.js";
3
3
  //#region src/bin.ts
4
- main();
4
+ main({ profile: parseProfileArg(process.argv.slice(2)) });
5
5
  //#endregion
6
6
  export {};
7
7
 
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { main } from './index.js';\n\nvoid main();\n"],"mappings":";;;AAGK,MAAM"}
1
+ {"version":3,"file":"bin.js","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { main, parseProfileArg } from './index.js';\n\n// The OpenClaw daemon bundler launches this bin with no args → `default`\n// profile (integrations only, unchanged). The Alfe CLI launches it as\n// `node <bin> --profile claude-code` for a Claude Code session → memory +\n// voice + messaging tools on top.\nvoid main({ profile: parseProfileArg(process.argv.slice(2)) });\n"],"mappings":";;;AAOK,KAAK,EAAE,SAAS,gBAAgB,QAAQ,KAAK,MAAM,EAAE,CAAC,EAAE,CAAC"}
package/dist/index.cjs CHANGED
@@ -44,39 +44,70 @@ const SERVER_BIN_PATH = (0, node_url.fileURLToPath)(new URL("./bin.js", require(
44
44
  * `~/.alfe/config.toml`.
45
45
  */
46
46
  async function createServer(opts = {}) {
47
+ const profile = opts.profile ?? "default";
47
48
  let client = opts.client;
48
49
  let apiUrl = opts.apiUrl;
49
- if (!client || !apiUrl) {
50
+ let voiceClient = opts.voiceClient;
51
+ let voiceApiUrl = opts.voiceApiUrl;
52
+ if (!client || !apiUrl || profile === "claude-code" && !voiceClient && !voiceApiUrl) {
50
53
  const cfg = (0, _alfe_ai_config.resolveConfig)();
51
54
  client = client ?? new _alfe_ai_agent_api_client.AgentApiClient({
52
55
  apiKey: cfg.apiKey,
53
56
  apiUrl: cfg.apiUrl
54
57
  });
55
58
  apiUrl = apiUrl ?? cfg.apiUrl;
59
+ voiceApiUrl = voiceApiUrl ?? cfg.voiceServiceUrl;
60
+ voiceClient = voiceClient ?? new _alfe_ai_agent_api_client.AgentApiClient({
61
+ apiKey: cfg.apiKey,
62
+ apiUrl: cfg.voiceServiceUrl
63
+ });
56
64
  }
57
65
  const identity = opts.identity ?? await client.whoami();
58
66
  const ctx = {
59
67
  client,
60
68
  apiUrl,
61
69
  agentId: identity.agentId,
62
- tenantId: identity.tenantId
70
+ tenantId: identity.tenantId,
71
+ voiceApiUrl,
72
+ voiceClient
63
73
  };
64
74
  const server = new _modelcontextprotocol_sdk_server_mcp_js.McpServer({
65
75
  name: SERVER_NAME,
66
76
  version: SERVER_VERSION
67
77
  });
68
78
  (0, _alfe_ai_mcp_tools.registerIntegrationsTools)(server, ctx);
79
+ if (profile === "claude-code") {
80
+ (0, _alfe_ai_mcp_tools.registerMemoryTools)(server, ctx);
81
+ (0, _alfe_ai_mcp_tools.registerVoiceTools)(server, ctx);
82
+ (0, _alfe_ai_mcp_tools.registerMessagingTools)(server, ctx);
83
+ }
69
84
  return server;
70
85
  }
71
86
  /**
87
+ * Parse the server profile out of a raw argv slice. Accepts both
88
+ * `--profile claude-code` and `--profile=claude-code`. Unknown or missing
89
+ * values resolve to `default`, so the OpenClaw bundler (which launches the
90
+ * bin with no args) always gets the integrations-only surface.
91
+ */
92
+ function parseProfileArg(argv) {
93
+ for (let i = 0; i < argv.length; i++) {
94
+ const arg = argv[i];
95
+ let value;
96
+ if (arg === "--profile") value = argv[i + 1];
97
+ else if (arg.startsWith("--profile=")) value = arg.slice(10);
98
+ if (value === "claude-code") return "claude-code";
99
+ }
100
+ return "default";
101
+ }
102
+ /**
72
103
  * Entry point — boot the server on stdio. Used by `bin.ts`. Any
73
104
  * startup failure is fatal: log and exit non-zero so the bundler's
74
105
  * connection attempt surfaces a clear error rather than a hung
75
106
  * handshake.
76
107
  */
77
- async function main() {
108
+ async function main(opts = {}) {
78
109
  try {
79
- const server = await createServer();
110
+ const server = await createServer({ profile: opts.profile });
80
111
  const transport = new _modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport();
81
112
  await server.connect(transport);
82
113
  } catch (err) {
@@ -93,3 +124,4 @@ exports.SERVER_NAME = SERVER_NAME;
93
124
  exports.SERVER_VERSION = SERVER_VERSION;
94
125
  exports.createServer = createServer;
95
126
  exports.main = main;
127
+ exports.parseProfileArg = parseProfileArg;
package/dist/index.d.cts CHANGED
@@ -10,6 +10,26 @@ interface AgentApiClientConfig {
10
10
  apiKey: string;
11
11
  apiUrl: string;
12
12
  }
13
+ /**
14
+ * The broad-news providers behind the metered `services/news` Lambda. The
15
+ * server validates this with a zod enum; a value outside the union is an
16
+ * unpriceable product, so keep the literal union in lockstep with the service.
17
+ */
18
+ type NewsProvider = "apitube" | "newsdata";
19
+ /** One normalized article. `sentiment` is provider-shaped (APITube supplies it). */
20
+ interface NewsArticle {
21
+ title: string;
22
+ url: string;
23
+ source: string;
24
+ publishedAt: string;
25
+ snippet: string;
26
+ sentiment?: unknown;
27
+ }
28
+ /** Provider-agnostic result — the server normalizes every adapter to this. */
29
+ interface NewsResult {
30
+ articles: NewsArticle[];
31
+ provider: string;
32
+ }
13
33
  interface RemoteSessionInfo {
14
34
  sessionId: string;
15
35
  agentId: string;
@@ -424,23 +444,33 @@ declare class AgentApiClient {
424
444
  * Pattern A: multi-account credential fetch for cTrader.
425
445
  *
426
446
  * Unlike atlassian/salesforce (one Connection row per account/site), a
427
- * single cTrader OAuth grant covers ALL of the user's trading accounts on
428
- * one shared access token only the `ctidTraderAccountId` and the
429
- * protobuf socket `host` (live vs demo) differ per account. So this returns
430
- * the flattened *trading accounts* array off the primary cTrader Connection
431
- * (mirroring how atlassian exposes `availableSites`), with the shared app
432
- * credentials (`clientId`/`clientSecret`) and the connection `accessToken`
433
- * hoisted to the top level the MCP server app-auths ONCE and account-auths
434
- * per selected `ctidTraderAccountId`.
447
+ * cTrader is MULTI-grant per agent: an agent may connect several distinct
448
+ * cTrader logins, each its own Connection row keyed on `accountIdentifier =
449
+ * ctid:<userId>` (Phase 1). This aggregates the *trading accounts* across
450
+ * ALL of those Connection rows each row contributes its `availableAccounts`
451
+ * flattened, and every account carries ITS OWN grant's `accessToken` (the
452
+ * token that authenticates that account against the cTrader Open API). One
453
+ * OAuth grant still covers all accounts under that single login on one shared
454
+ * token; only the `ctidTraderAccountId` and the protobuf socket `host` (live
455
+ * vs demo) differ within a grant. Across grants the tokens differ, so the
456
+ * token is now PER-ACCOUNT rather than hoisted to the top level.
435
457
  *
436
458
  * `host` per account is derived from the account's `isLive` flag
437
459
  * (`live.ctraderapi.com` / `demo.ctraderapi.com`) — the same mapping the
438
460
  * connect provider applies server-side when an account is auto-selected.
439
461
  *
440
- * Only the primary (first, most-specific-scope) cTrader Connection is used;
441
- * cTrader is single-grant, so there is normally exactly one. `clientId` /
442
- * `clientSecret` are the SST-sourced global app credentials the connect
443
- * endpoint injects never persisted on the connection.
462
+ * `clientId` / `clientSecret` are the SST-sourced GLOBAL app credentials the
463
+ * connect endpoint injects identical across every Connection row (one
464
+ * cTrader app), never persisted on a connection. We take them from the first
465
+ * row that carries them.
466
+ *
467
+ * Accounts are deduped on `ctidTraderAccountId` first-wins: Spotware ids are
468
+ * globally unique across logins, so a duplicate can only appear if the same
469
+ * account somehow surfaced under two grants — first-wins keeps it
470
+ * deterministic.
471
+ *
472
+ * `accounts` may be empty (no cTrader Connection at all), in which case we
473
+ * return empty creds rather than throwing.
444
474
  */
445
475
  getCTraderAccounts(): Promise<{
446
476
  accounts: {
@@ -449,10 +479,10 @@ declare class AgentApiClient {
449
479
  isLive: boolean;
450
480
  brokerName?: string;
451
481
  accountNumber?: string;
482
+ accessToken: string;
452
483
  }[];
453
484
  clientId: string;
454
485
  clientSecret: string;
455
- accessToken: string;
456
486
  }>;
457
487
  /**
458
488
  * @deprecated Returns a single primary credential blob (legacy "pick-the-
@@ -491,6 +521,41 @@ declare class AgentApiClient {
491
521
  scopes: string;
492
522
  }[];
493
523
  }>;
524
+ /**
525
+ * Pattern A: provider-parameterized multi-account credential fetch for the
526
+ * social connectors (Bluesky, and the approval-gated backlog: X, Meta,
527
+ * Threads, LinkedIn, Pinterest, TikTok, Reddit, YouTube).
528
+ *
529
+ * Unlike the bespoke `getGithubAccounts()` / `getXeroAccounts()` shapes,
530
+ * this returns a UNIFORM normalized account shape so `@alfe.ai/social-mcp`'s
531
+ * shared driver can require a single `account` selector on every
532
+ * credential-touching tool regardless of platform. The backend
533
+ * `api-agents/{provider}/accounts` route is already provider-generic; this
534
+ * is the client-side normalization the plan (`do-we-need-any-moonlit-toucan`
535
+ * Phase 0, step 5) calls for.
536
+ *
537
+ * `accountIdentifier` is the stable per-account selector the LLM should
538
+ * pass back (for Bluesky: the account DID). `accessToken` carries whatever
539
+ * the provider's `buildCredentialsResponse` bundles (for Bluesky: the JSON
540
+ * session bundle — the driver parses the `accessJwt` out of it, or reads the
541
+ * top-level `accessJwt` from `providerMetadata`-adjacent fields). Everything
542
+ * else the driver needs for routing (handle, pdsHost, did, …) is on
543
+ * `providerMetadata`.
544
+ *
545
+ * Token refresh is delegated to connect (never done in-plugin) via
546
+ * `POST /agent/connect/{provider}/refresh` — not exposed here.
547
+ */
548
+ getSocialAccounts(provider: string): Promise<{
549
+ provider: string;
550
+ accounts: {
551
+ connectionId: string;
552
+ accountIdentifier: string;
553
+ displayName: string | null;
554
+ accessToken: string;
555
+ providerMetadata: Record<string, unknown>;
556
+ connectedAt: string;
557
+ }[];
558
+ }>;
494
559
  /**
495
560
  * @deprecated Returns a single primary credential blob (legacy "pick-the-
496
561
  * default-connection" shape). Use `getXeroAccounts()` for the multi-
@@ -1299,6 +1364,13 @@ declare class AgentApiClient {
1299
1364
  synced: true;
1300
1365
  syncedAt: string;
1301
1366
  }>;
1367
+ sendSms(args: {
1368
+ to: string;
1369
+ body: string;
1370
+ }): Promise<{
1371
+ sent: boolean;
1372
+ sid: string;
1373
+ }>;
1302
1374
  searchWeb(params: {
1303
1375
  query: string;
1304
1376
  count?: number;
@@ -1315,6 +1387,25 @@ declare class AgentApiClient {
1315
1387
  count?: number;
1316
1388
  freshness?: string;
1317
1389
  }): Promise<unknown>;
1390
+ /** Search news across the selected provider's corpus. → POST /agent/news/search */
1391
+ newsSearch(params: {
1392
+ query: string;
1393
+ provider?: NewsProvider;
1394
+ source?: string;
1395
+ from?: string;
1396
+ to?: string;
1397
+ language?: string;
1398
+ category?: string;
1399
+ limit?: number;
1400
+ }): Promise<NewsResult>;
1401
+ /** Top headlines for the selected provider. → POST /agent/news/headlines */
1402
+ newsHeadlines(params?: {
1403
+ provider?: NewsProvider;
1404
+ category?: string;
1405
+ source?: string;
1406
+ language?: string;
1407
+ limit?: number;
1408
+ }): Promise<NewsResult>;
1318
1409
  /**
1319
1410
  * Semantic search across the agent's member scopes. Fan-out is gated
1320
1411
  * server-side by `listScopes` set-inclusion (fail-closed). Pass
@@ -1465,6 +1556,20 @@ declare const SERVER_VERSION: string;
1465
1556
  * lives; consumers shouldn't have to crawl `package.json` for it.
1466
1557
  */
1467
1558
  declare const SERVER_BIN_PATH: string;
1559
+ /**
1560
+ * Which tool surface the server exposes.
1561
+ *
1562
+ * - `default` (the OpenClaw daemon bundler's path — the bin is launched with
1563
+ * no `--profile`) registers ONLY the integrations tools. OpenClaw agents
1564
+ * consume this same server and already get `memory_*` from the
1565
+ * `@alfe.ai/openclaw-memory-cloud` plugin, so registering memory here would
1566
+ * DOUBLE their tool surface. Do not add tools to this profile without
1567
+ * confirming they don't already ship as an OpenClaw plugin.
1568
+ * - `claude-code` additionally registers memory + voice + messaging tools —
1569
+ * for a Claude Code session that has no Alfe plugins and needs those
1570
+ * capabilities delivered via MCP.
1571
+ */
1572
+ type ServerProfile = 'default' | 'claude-code';
1468
1573
  interface ServerOptions {
1469
1574
  /**
1470
1575
  * Optional override for the API client — tests inject a fake so the
@@ -1478,6 +1583,20 @@ interface ServerOptions {
1478
1583
  };
1479
1584
  /** Override apiUrl reported in the ToolContext. Defaults to the resolved CLI config. */
1480
1585
  apiUrl?: string;
1586
+ /**
1587
+ * Tool surface to register. Defaults to `default` (integrations only) so
1588
+ * the OpenClaw bundler path is unchanged. `claude-code` adds memory + voice
1589
+ * + messaging.
1590
+ */
1591
+ profile?: ServerProfile;
1592
+ /**
1593
+ * Optional override for the voice-service client — tests inject a fake.
1594
+ * Only consumed by the `claude-code` profile's voice tools. When omitted
1595
+ * (and not resolvable from config) the voice tools fall back to `client`.
1596
+ */
1597
+ voiceClient?: AgentApiClient;
1598
+ /** Override voice-service apiUrl. Defaults to the resolved CLI config's `voiceServiceUrl`. */
1599
+ voiceApiUrl?: string;
1481
1600
  }
1482
1601
  /**
1483
1602
  * Build a configured `McpServer` with all thin-slice tools registered.
@@ -1489,15 +1608,24 @@ interface ServerOptions {
1489
1608
  * `~/.alfe/config.toml`.
1490
1609
  */
1491
1610
  declare function createServer(opts?: ServerOptions): Promise<McpServer>;
1611
+ /**
1612
+ * Parse the server profile out of a raw argv slice. Accepts both
1613
+ * `--profile claude-code` and `--profile=claude-code`. Unknown or missing
1614
+ * values resolve to `default`, so the OpenClaw bundler (which launches the
1615
+ * bin with no args) always gets the integrations-only surface.
1616
+ */
1617
+ declare function parseProfileArg(argv: string[]): ServerProfile;
1492
1618
  /**
1493
1619
  * Entry point — boot the server on stdio. Used by `bin.ts`. Any
1494
1620
  * startup failure is fatal: log and exit non-zero so the bundler's
1495
1621
  * connection attempt surfaces a clear error rather than a hung
1496
1622
  * handshake.
1497
1623
  */
1498
- declare function main(): Promise<void>;
1624
+ declare function main(opts?: {
1625
+ profile?: ServerProfile;
1626
+ }): Promise<void>;
1499
1627
  //# sourceMappingURL=index.d.ts.map
1500
1628
 
1501
1629
  //#endregion
1502
- export { SERVER_BIN_PATH, SERVER_NAME, SERVER_VERSION, ServerOptions, createServer, main };
1630
+ export { SERVER_BIN_PATH, SERVER_NAME, SERVER_VERSION, ServerOptions, ServerProfile, createServer, main, parseProfileArg };
1503
1631
  //# sourceMappingURL=index.d.cts.map