@linkedapi/mcp 0.3.11 → 1.0.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.
Files changed (140) hide show
  1. package/.github/workflows/merge-main.yaml +9 -9
  2. package/.github/workflows/pr-main.yaml +4 -4
  3. package/README.md +9 -0
  4. package/dist/index.js +42 -9
  5. package/dist/index.js.map +1 -1
  6. package/dist/linked-api-server.d.ts +7 -4
  7. package/dist/linked-api-server.d.ts.map +1 -1
  8. package/dist/linked-api-server.js +62 -8
  9. package/dist/linked-api-server.js.map +1 -1
  10. package/dist/linked-api-tools.d.ts +21 -4
  11. package/dist/linked-api-tools.d.ts.map +1 -1
  12. package/dist/linked-api-tools.js +54 -28
  13. package/dist/linked-api-tools.js.map +1 -1
  14. package/dist/tools/admin-connect-account.d.ts +14 -0
  15. package/dist/tools/admin-connect-account.d.ts.map +1 -0
  16. package/dist/tools/admin-connect-account.js +27 -0
  17. package/dist/tools/admin-connect-account.js.map +1 -0
  18. package/dist/tools/admin-disconnect-account.d.ts +16 -0
  19. package/dist/tools/admin-disconnect-account.d.ts.map +1 -0
  20. package/dist/tools/admin-disconnect-account.js +35 -0
  21. package/dist/tools/admin-disconnect-account.js.map +1 -0
  22. package/dist/tools/admin-get-accounts.d.ts +14 -0
  23. package/dist/tools/admin-get-accounts.d.ts.map +1 -0
  24. package/dist/tools/admin-get-accounts.js +27 -0
  25. package/dist/tools/admin-get-accounts.js.map +1 -0
  26. package/dist/tools/admin-get-limits-usage.d.ts +20 -0
  27. package/dist/tools/admin-get-limits-usage.d.ts.map +1 -0
  28. package/dist/tools/admin-get-limits-usage.js +35 -0
  29. package/dist/tools/admin-get-limits-usage.js.map +1 -0
  30. package/dist/tools/admin-get-seats.d.ts +18 -0
  31. package/dist/tools/admin-get-seats.d.ts.map +1 -0
  32. package/dist/tools/admin-get-seats.js +27 -0
  33. package/dist/tools/admin-get-seats.js.map +1 -0
  34. package/dist/tools/admin-get-subscription-status.d.ts +14 -0
  35. package/dist/tools/admin-get-subscription-status.d.ts.map +1 -0
  36. package/dist/tools/admin-get-subscription-status.js +27 -0
  37. package/dist/tools/admin-get-subscription-status.js.map +1 -0
  38. package/dist/tools/admin-regenerate-token.d.ts +16 -0
  39. package/dist/tools/admin-regenerate-token.d.ts.map +1 -0
  40. package/dist/tools/admin-regenerate-token.js +35 -0
  41. package/dist/tools/admin-regenerate-token.js.map +1 -0
  42. package/dist/tools/admin-reset-limits.d.ts +16 -0
  43. package/dist/tools/admin-reset-limits.d.ts.map +1 -0
  44. package/dist/tools/admin-reset-limits.js +35 -0
  45. package/dist/tools/admin-reset-limits.js.map +1 -0
  46. package/dist/tools/admin-set-limits.d.ts +26 -0
  47. package/dist/tools/admin-set-limits.d.ts.map +1 -0
  48. package/dist/tools/admin-set-limits.js +68 -0
  49. package/dist/tools/admin-set-limits.js.map +1 -0
  50. package/dist/tools/admin-set-seats.d.ts +24 -0
  51. package/dist/tools/admin-set-seats.d.ts.map +1 -0
  52. package/dist/tools/admin-set-seats.js +47 -0
  53. package/dist/tools/admin-set-seats.js.map +1 -0
  54. package/dist/tools/comment-on-post.d.ts.map +1 -1
  55. package/dist/tools/comment-on-post.js +1 -1
  56. package/dist/tools/comment-on-post.js.map +1 -1
  57. package/dist/tools/create-post.js +1 -1
  58. package/dist/tools/create-post.js.map +1 -1
  59. package/dist/tools/execute-custom-workflow.d.ts.map +1 -1
  60. package/dist/tools/execute-custom-workflow.js +1 -1
  61. package/dist/tools/execute-custom-workflow.js.map +1 -1
  62. package/dist/tools/get-conversation.d.ts +3 -1
  63. package/dist/tools/get-conversation.d.ts.map +1 -1
  64. package/dist/tools/get-conversation.js +20 -3
  65. package/dist/tools/get-conversation.js.map +1 -1
  66. package/dist/tools/get-workflow-result.d.ts +3 -1
  67. package/dist/tools/get-workflow-result.d.ts.map +1 -1
  68. package/dist/tools/get-workflow-result.js +7 -4
  69. package/dist/tools/get-workflow-result.js.map +1 -1
  70. package/dist/tools/nv-get-conversation.d.ts +3 -1
  71. package/dist/tools/nv-get-conversation.d.ts.map +1 -1
  72. package/dist/tools/nv-get-conversation.js +20 -3
  73. package/dist/tools/nv-get-conversation.js.map +1 -1
  74. package/dist/tools/nv-send-message.js +1 -1
  75. package/dist/tools/nv-send-message.js.map +1 -1
  76. package/dist/tools/react-to-post.js +1 -1
  77. package/dist/tools/react-to-post.js.map +1 -1
  78. package/dist/tools/remove-connection.js +1 -1
  79. package/dist/tools/remove-connection.js.map +1 -1
  80. package/dist/tools/send-connection-request.js +1 -1
  81. package/dist/tools/send-connection-request.js.map +1 -1
  82. package/dist/tools/send-message.d.ts.map +1 -1
  83. package/dist/tools/send-message.js +1 -1
  84. package/dist/tools/send-message.js.map +1 -1
  85. package/dist/tools/withdraw-connection-request.js +1 -1
  86. package/dist/tools/withdraw-connection-request.js.map +1 -1
  87. package/dist/utils/admin-tool.d.ts +14 -0
  88. package/dist/utils/admin-tool.d.ts.map +1 -0
  89. package/dist/utils/admin-tool.js +10 -0
  90. package/dist/utils/admin-tool.js.map +1 -0
  91. package/dist/utils/define-request-timeout.d.ts.map +1 -1
  92. package/dist/utils/define-request-timeout.js +16 -4
  93. package/dist/utils/define-request-timeout.js.map +1 -1
  94. package/dist/utils/execute-with-progress.d.ts +7 -2
  95. package/dist/utils/execute-with-progress.d.ts.map +1 -1
  96. package/dist/utils/execute-with-progress.js +19 -9
  97. package/dist/utils/execute-with-progress.js.map +1 -1
  98. package/dist/utils/handle-linked-api-error.d.ts +1 -1
  99. package/dist/utils/handle-linked-api-error.d.ts.map +1 -1
  100. package/dist/utils/handle-linked-api-error.js +10 -0
  101. package/dist/utils/handle-linked-api-error.js.map +1 -1
  102. package/dist/utils/json-http-transport.d.ts.map +1 -1
  103. package/dist/utils/json-http-transport.js +4 -3
  104. package/dist/utils/json-http-transport.js.map +1 -1
  105. package/dist/utils/linked-api-tool.d.ts +10 -14
  106. package/dist/utils/linked-api-tool.d.ts.map +1 -1
  107. package/dist/utils/linked-api-tool.js +5 -6
  108. package/dist/utils/linked-api-tool.js.map +1 -1
  109. package/package.json +2 -2
  110. package/src/index.ts +46 -9
  111. package/src/linked-api-server.ts +87 -16
  112. package/src/linked-api-tools.ts +81 -31
  113. package/src/tools/admin-connect-account.ts +34 -0
  114. package/src/tools/admin-disconnect-account.ts +40 -0
  115. package/src/tools/admin-get-accounts.ts +30 -0
  116. package/src/tools/admin-get-limits-usage.ts +42 -0
  117. package/src/tools/admin-get-seats.ts +34 -0
  118. package/src/tools/admin-get-subscription-status.ts +33 -0
  119. package/src/tools/admin-regenerate-token.ts +43 -0
  120. package/src/tools/admin-reset-limits.ts +39 -0
  121. package/src/tools/admin-set-limits.ts +75 -0
  122. package/src/tools/admin-set-seats.ts +52 -0
  123. package/src/tools/comment-on-post.ts +2 -1
  124. package/src/tools/create-post.ts +1 -1
  125. package/src/tools/execute-custom-workflow.ts +2 -1
  126. package/src/tools/get-conversation.ts +27 -3
  127. package/src/tools/get-workflow-result.ts +10 -3
  128. package/src/tools/nv-get-conversation.ts +27 -3
  129. package/src/tools/nv-send-message.ts +1 -1
  130. package/src/tools/react-to-post.ts +1 -1
  131. package/src/tools/remove-connection.ts +1 -1
  132. package/src/tools/send-connection-request.ts +1 -1
  133. package/src/tools/send-message.ts +2 -1
  134. package/src/tools/withdraw-connection-request.ts +1 -1
  135. package/src/utils/admin-tool.ts +22 -0
  136. package/src/utils/define-request-timeout.ts +16 -4
  137. package/src/utils/execute-with-progress.ts +37 -19
  138. package/src/utils/handle-linked-api-error.ts +12 -1
  139. package/src/utils/json-http-transport.ts +4 -3
  140. package/src/utils/linked-api-tool.ts +16 -18
@@ -0,0 +1,30 @@
1
+ import { LinkedApiAdmin, TAccountsResult } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminGetAccountsTool extends AdminTool<Record<string, never>, TAccountsResult> {
8
+ public readonly name = 'admin_get_accounts';
9
+ protected readonly schema = z.object({});
10
+
11
+ public override async execute({
12
+ admin,
13
+ }: {
14
+ admin: LinkedApiAdmin;
15
+ args: Record<string, never>;
16
+ }): Promise<TAccountsResult> {
17
+ return await admin.accounts.getAll();
18
+ }
19
+
20
+ public override getTool(): Tool {
21
+ return {
22
+ name: this.name,
23
+ description: 'Get all connected LinkedIn accounts and pending connection sessions.',
24
+ inputSchema: {
25
+ type: 'object',
26
+ properties: {},
27
+ },
28
+ };
29
+ }
30
+ }
@@ -0,0 +1,42 @@
1
+ import { LinkedApiAdmin, TGetLimitsUsageParams, TLimitUsage } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminGetLimitsUsageTool extends AdminTool<
8
+ TGetLimitsUsageParams,
9
+ { usage: Array<TLimitUsage> }
10
+ > {
11
+ public readonly name = 'admin_get_limits_usage';
12
+ protected readonly schema = z.object({
13
+ accountId: z.string(),
14
+ });
15
+
16
+ public override async execute({
17
+ admin,
18
+ args,
19
+ }: {
20
+ admin: LinkedApiAdmin;
21
+ args: TGetLimitsUsageParams;
22
+ }): Promise<{ usage: Array<TLimitUsage> }> {
23
+ return await admin.limits.getUsage(args);
24
+ }
25
+
26
+ public override getTool(): Tool {
27
+ return {
28
+ name: this.name,
29
+ description: 'Get current usage against configured rate limits for an account.',
30
+ inputSchema: {
31
+ type: 'object',
32
+ properties: {
33
+ accountId: {
34
+ type: 'string',
35
+ description: 'Account UUID',
36
+ },
37
+ },
38
+ required: ['accountId'],
39
+ },
40
+ };
41
+ }
42
+ }
@@ -0,0 +1,34 @@
1
+ import { LinkedApiAdmin, TSubscriptionSeat } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminGetSeatsTool extends AdminTool<
8
+ Record<string, never>,
9
+ { seats: Array<TSubscriptionSeat> }
10
+ > {
11
+ public readonly name = 'admin_get_seats';
12
+ protected readonly schema = z.object({});
13
+
14
+ public override async execute({
15
+ admin,
16
+ }: {
17
+ admin: LinkedApiAdmin;
18
+ args: Record<string, never>;
19
+ }): Promise<{ seats: Array<TSubscriptionSeat> }> {
20
+ return await admin.subscription.getSeats();
21
+ }
22
+
23
+ public override getTool(): Tool {
24
+ return {
25
+ name: this.name,
26
+ description:
27
+ 'Get active subscription seats. Each seat allows one connected LinkedIn account. Seat types: core (standard) and plus (includes Sales Navigator).',
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {},
31
+ },
32
+ };
33
+ }
34
+ }
@@ -0,0 +1,33 @@
1
+ import { LinkedApiAdmin, TSubscriptionStatus } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminGetSubscriptionStatusTool extends AdminTool<
8
+ Record<string, never>,
9
+ TSubscriptionStatus
10
+ > {
11
+ public readonly name = 'admin_get_subscription_status';
12
+ protected readonly schema = z.object({});
13
+
14
+ public override async execute({
15
+ admin,
16
+ }: {
17
+ admin: LinkedApiAdmin;
18
+ args: Record<string, never>;
19
+ }): Promise<TSubscriptionStatus> {
20
+ return await admin.subscription.getStatus();
21
+ }
22
+
23
+ public override getTool(): Tool {
24
+ return {
25
+ name: this.name,
26
+ description: 'Get current subscription status, trial eligibility, and cancellation schedule.',
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {},
30
+ },
31
+ };
32
+ }
33
+ }
@@ -0,0 +1,43 @@
1
+ import { LinkedApiAdmin, TRegenerateTokenParams, TRegenerateTokenResult } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminRegenerateTokenTool extends AdminTool<
8
+ TRegenerateTokenParams,
9
+ TRegenerateTokenResult
10
+ > {
11
+ public readonly name = 'admin_regenerate_token';
12
+ protected readonly schema = z.object({
13
+ accountId: z.string(),
14
+ });
15
+
16
+ public override async execute({
17
+ admin,
18
+ args,
19
+ }: {
20
+ admin: LinkedApiAdmin;
21
+ args: TRegenerateTokenParams;
22
+ }): Promise<TRegenerateTokenResult> {
23
+ return await admin.accounts.regenerateIdentificationToken(args);
24
+ }
25
+
26
+ public override getTool(): Tool {
27
+ return {
28
+ name: this.name,
29
+ description:
30
+ 'Regenerate identification token for an account. The old token becomes invalid immediately.',
31
+ inputSchema: {
32
+ type: 'object',
33
+ properties: {
34
+ accountId: {
35
+ type: 'string',
36
+ description: 'UUID of the account',
37
+ },
38
+ },
39
+ required: ['accountId'],
40
+ },
41
+ };
42
+ }
43
+ }
@@ -0,0 +1,39 @@
1
+ import { LinkedApiAdmin, TResetLimitsParams } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminResetLimitsTool extends AdminTool<TResetLimitsParams, void> {
8
+ public readonly name = 'admin_reset_limits';
9
+ protected readonly schema = z.object({
10
+ accountId: z.string(),
11
+ });
12
+
13
+ public override async execute({
14
+ admin,
15
+ args,
16
+ }: {
17
+ admin: LinkedApiAdmin;
18
+ args: TResetLimitsParams;
19
+ }): Promise<void> {
20
+ await admin.limits.resetToDefaults(args);
21
+ }
22
+
23
+ public override getTool(): Tool {
24
+ return {
25
+ name: this.name,
26
+ description: 'Reset all rate limits for an account to the system defaults.',
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {
30
+ accountId: {
31
+ type: 'string',
32
+ description: 'Account UUID',
33
+ },
34
+ },
35
+ required: ['accountId'],
36
+ },
37
+ };
38
+ }
39
+ }
@@ -0,0 +1,75 @@
1
+ import { LinkedApiAdmin, TSetLimitsParams } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminSetLimitsTool extends AdminTool<TSetLimitsParams, void> {
8
+ public readonly name = 'admin_set_limits';
9
+ protected readonly schema = z.object({
10
+ accountId: z.string(),
11
+ limits: z.array(
12
+ z.object({
13
+ category: z.string(),
14
+ period: z.enum(['daily', 'weekly', 'monthly']),
15
+ maxValue: z.number().int().min(0),
16
+ isEnabled: z.boolean().optional(),
17
+ }),
18
+ ),
19
+ });
20
+
21
+ public override async execute({
22
+ admin,
23
+ args,
24
+ }: {
25
+ admin: LinkedApiAdmin;
26
+ args: TSetLimitsParams;
27
+ }): Promise<void> {
28
+ await admin.limits.set(args);
29
+ }
30
+
31
+ public override getTool(): Tool {
32
+ return {
33
+ name: this.name,
34
+ description:
35
+ 'Set rate limits for an account. Only specified limits are created or updated; other limits remain unchanged. Categories: stPersonProfileViews, stCompanyPageViews, stConnectionRequests, stMessages, stSearchQueries, stReactions, stComments, stPosts, nvPersonProfileViews, nvCompanyPageViews, nvMessages.',
36
+ inputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ accountId: {
40
+ type: 'string',
41
+ description: 'Account UUID',
42
+ },
43
+ limits: {
44
+ type: 'array',
45
+ description: 'Array of limit configurations',
46
+ items: {
47
+ type: 'object',
48
+ properties: {
49
+ category: {
50
+ type: 'string',
51
+ description: 'Limit category',
52
+ },
53
+ period: {
54
+ type: 'string',
55
+ enum: ['daily', 'weekly', 'monthly'],
56
+ description: 'Limit period',
57
+ },
58
+ maxValue: {
59
+ type: 'number',
60
+ description: 'Maximum allowed actions (>= 0)',
61
+ },
62
+ isEnabled: {
63
+ type: 'boolean',
64
+ description: 'Whether this limit is enforced (default: true)',
65
+ },
66
+ },
67
+ required: ['category', 'period', 'maxValue'],
68
+ },
69
+ },
70
+ },
71
+ required: ['accountId', 'limits'],
72
+ },
73
+ };
74
+ }
75
+ }
@@ -0,0 +1,52 @@
1
+ import { LinkedApiAdmin, TSetSeatsParams, TSetSeatsResult } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ import { AdminTool } from '../utils/admin-tool.js';
6
+
7
+ export class AdminSetSeatsTool extends AdminTool<TSetSeatsParams, TSetSeatsResult> {
8
+ public readonly name = 'admin_set_seats';
9
+ protected readonly schema = z.object({
10
+ quantity: z.number().int().min(1).max(1000),
11
+ seatType: z.enum(['core', 'plus']),
12
+ billingPeriod: z.enum(['month', 'year']),
13
+ });
14
+
15
+ public override async execute({
16
+ admin,
17
+ args,
18
+ }: {
19
+ admin: LinkedApiAdmin;
20
+ args: TSetSeatsParams;
21
+ }): Promise<TSetSeatsResult> {
22
+ return await admin.subscription.setSeats(args);
23
+ }
24
+
25
+ public override getTool(): Tool {
26
+ return {
27
+ name: this.name,
28
+ description:
29
+ 'Set number of subscription seats. Returns checkout link if no active subscription, otherwise updates immediately.',
30
+ inputSchema: {
31
+ type: 'object',
32
+ properties: {
33
+ quantity: {
34
+ type: 'number',
35
+ description: 'Number of seats (1-1000)',
36
+ },
37
+ seatType: {
38
+ type: 'string',
39
+ enum: ['core', 'plus'],
40
+ description: 'Seat type. "plus" unlocks Sales Navigator actions.',
41
+ },
42
+ billingPeriod: {
43
+ type: 'string',
44
+ enum: ['month', 'year'],
45
+ description: 'Billing period',
46
+ },
47
+ },
48
+ required: ['quantity', 'seatType', 'billingPeriod'],
49
+ },
50
+ };
51
+ }
52
+ }
@@ -16,7 +16,8 @@ export class CommentOnPostTool extends OperationTool<TCommentOnPostParams, unkno
16
16
  public override getTool(): Tool {
17
17
  return {
18
18
  name: this.name,
19
- description: 'Allows you to leave a comment on a post (st.commentOnPost action).',
19
+ description:
20
+ 'Allows you to leave a comment on a post (st.commentOnPost action). If this workflow is still running, do not retry this tool; retrying can post duplicate comments.',
20
21
  inputSchema: {
21
22
  type: 'object',
22
23
  properties: {
@@ -26,7 +26,7 @@ export class CreatePostTool extends OperationTool<TCreatePostParams, unknown> {
26
26
  return {
27
27
  name: this.name,
28
28
  description:
29
- 'Creates a new LinkedIn post with optional media attachments (st.createPost action).',
29
+ 'Creates a new LinkedIn post with optional media attachments (st.createPost action). If this workflow is still running, do not retry this tool; retrying can create duplicate posts.',
30
30
  inputSchema: {
31
31
  type: 'object',
32
32
  properties: {
@@ -17,7 +17,8 @@ export class ExecuteCustomWorkflowTool extends OperationTool<
17
17
  public override getTool(): Tool {
18
18
  return {
19
19
  name: this.name,
20
- description: 'Execute a custom workflow definition',
20
+ description:
21
+ 'Execute a custom workflow definition. If this workflow is still running, do not retry this tool; retrying can duplicate any write actions inside the custom workflow.',
21
22
  inputSchema: {
22
23
  type: 'object',
23
24
  properties: { definition: { type: 'object' } },
@@ -1,8 +1,14 @@
1
- import LinkedApi, { TConversationPollResult, TMappedResponse } from '@linkedapi/node';
1
+ import LinkedApi, {
2
+ LinkedApiWorkflowTimeoutError,
3
+ TConversationPollResult,
4
+ TMappedResponse,
5
+ } from '@linkedapi/node';
2
6
  import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
7
  import z from 'zod';
4
8
 
9
+ import { executeWithProgress } from '../utils/execute-with-progress.js';
5
10
  import { LinkedApiTool } from '../utils/linked-api-tool.js';
11
+ import { LinkedApiProgressNotification } from '../utils/types.js';
6
12
 
7
13
  export class GetConversationTool extends LinkedApiTool<
8
14
  { personUrl: string; since?: string },
@@ -17,18 +23,36 @@ export class GetConversationTool extends LinkedApiTool<
17
23
  public override async execute({
18
24
  linkedapi,
19
25
  args: { personUrl, since },
26
+ workflowTimeout,
27
+ progressToken,
28
+ progressCallback,
20
29
  }: {
21
30
  linkedapi: LinkedApi;
22
31
  args: { personUrl: string; since?: string };
23
32
  workflowTimeout: number;
24
33
  progressToken?: string | number;
34
+ progressCallback: (progress: LinkedApiProgressNotification) => void;
25
35
  }): Promise<TMappedResponse<TConversationPollResult>> {
26
36
  const conversations = await this.getConversation(linkedapi, personUrl, since);
27
37
  if (conversations.errors.length === 0) {
28
38
  return conversations;
29
39
  }
30
- const workflowId = await linkedapi.syncConversation.execute({ personUrl });
31
- await linkedapi.syncConversation.result(workflowId);
40
+ try {
41
+ await executeWithProgress({
42
+ progressCallback,
43
+ operation: linkedapi.syncConversation,
44
+ workflowTimeout,
45
+ params: { personUrl },
46
+ progressToken,
47
+ });
48
+ } catch (error) {
49
+ if (error instanceof LinkedApiWorkflowTimeoutError) {
50
+ error.message = `${error.message}
51
+
52
+ After get_workflow_result completes this sync workflow, call get_conversation again with the same personUrl to read the synchronized messages.`;
53
+ }
54
+ throw error;
55
+ }
32
56
  return await this.getConversation(linkedapi, personUrl, since);
33
57
  }
34
58
 
@@ -4,6 +4,7 @@ import z from 'zod';
4
4
 
5
5
  import { executeWithProgress } from '../utils/execute-with-progress.js';
6
6
  import { LinkedApiTool } from '../utils/linked-api-tool.js';
7
+ import { LinkedApiProgressNotification } from '../utils/types.js';
7
8
 
8
9
  interface IGetWorkflowResultParams {
9
10
  workflowId: string;
@@ -22,16 +23,21 @@ export class GetWorkflowResultTool extends LinkedApiTool<IGetWorkflowResultParam
22
23
  args: { workflowId, operationName },
23
24
  workflowTimeout,
24
25
  progressToken,
26
+ progressCallback,
25
27
  }: {
26
28
  linkedapi: LinkedApi;
27
29
  args: IGetWorkflowResultParams;
28
30
  workflowTimeout: number;
29
31
  progressToken?: string | number;
32
+ progressCallback: (progress: LinkedApiProgressNotification) => void;
30
33
  }): Promise<TMappedResponse<unknown>> {
31
34
  const operation = linkedapi.operations.find(
32
35
  (operation) => operation.operationName === operationName,
33
36
  )!;
34
- return await executeWithProgress(this.progressCallback, operation, workflowTimeout, {
37
+ return await executeWithProgress({
38
+ progressCallback,
39
+ operation,
40
+ workflowTimeout,
35
41
  workflowId,
36
42
  progressToken,
37
43
  });
@@ -47,12 +53,13 @@ export class GetWorkflowResultTool extends LinkedApiTool<IGetWorkflowResultParam
47
53
  properties: {
48
54
  workflowId: {
49
55
  type: 'string',
50
- description: 'The workflow ID provided in the background workflow status message',
56
+ description:
57
+ 'Required. The workflow ID provided in the background workflow status message.',
51
58
  },
52
59
  operationName: {
53
60
  type: 'string',
54
61
  description:
55
- 'Optional function name for proper type restoration (provided in background workflow status if available)',
62
+ 'Required. The operationName provided in the background workflow status message. Use the exact value so the result can be restored correctly.',
56
63
  },
57
64
  },
58
65
  required: ['workflowId', 'operationName'],
@@ -1,8 +1,14 @@
1
- import LinkedApi, { TConversationPollResult, TMappedResponse } from '@linkedapi/node';
1
+ import LinkedApi, {
2
+ LinkedApiWorkflowTimeoutError,
3
+ TConversationPollResult,
4
+ TMappedResponse,
5
+ } from '@linkedapi/node';
2
6
  import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
7
  import z from 'zod';
4
8
 
9
+ import { executeWithProgress } from '../utils/execute-with-progress.js';
5
10
  import { LinkedApiTool } from '../utils/linked-api-tool.js';
11
+ import { LinkedApiProgressNotification } from '../utils/types.js';
6
12
 
7
13
  export class NvGetConversationTool extends LinkedApiTool<
8
14
  { personUrl: string; since?: string },
@@ -17,18 +23,36 @@ export class NvGetConversationTool extends LinkedApiTool<
17
23
  public override async execute({
18
24
  linkedapi,
19
25
  args: { personUrl, since },
26
+ workflowTimeout,
27
+ progressToken,
28
+ progressCallback,
20
29
  }: {
21
30
  linkedapi: LinkedApi;
22
31
  args: { personUrl: string; since?: string };
23
32
  workflowTimeout: number;
24
33
  progressToken?: string | number;
34
+ progressCallback: (progress: LinkedApiProgressNotification) => void;
25
35
  }): Promise<TMappedResponse<TConversationPollResult>> {
26
36
  const conversations = await this.getConversation(linkedapi, personUrl, since);
27
37
  if (conversations.errors.length === 0) {
28
38
  return conversations;
29
39
  }
30
- const workflowId = await linkedapi.nvSyncConversation.execute({ personUrl });
31
- await linkedapi.nvSyncConversation.result(workflowId);
40
+ try {
41
+ await executeWithProgress({
42
+ progressCallback,
43
+ operation: linkedapi.nvSyncConversation,
44
+ workflowTimeout,
45
+ params: { personUrl },
46
+ progressToken,
47
+ });
48
+ } catch (error) {
49
+ if (error instanceof LinkedApiWorkflowTimeoutError) {
50
+ error.message = `${error.message}
51
+
52
+ After get_workflow_result completes this sync workflow, call nv_get_conversation again with the same personUrl to read the synchronized messages.`;
53
+ }
54
+ throw error;
55
+ }
32
56
  return await this.getConversation(linkedapi, personUrl, since);
33
57
  }
34
58
 
@@ -17,7 +17,7 @@ export class NvSendMessageTool extends OperationTool<TNvSendMessageParams, unkno
17
17
  return {
18
18
  name: this.name,
19
19
  description:
20
- 'Allows you to send a message to a person in Sales Navigator (nv.sendMessage action)',
20
+ 'Allows you to send a message to a person in Sales Navigator (nv.sendMessage action). If this workflow is still running, do not retry this tool; retrying can send duplicate Sales Navigator messages to the same person.',
21
21
  inputSchema: {
22
22
  type: 'object',
23
23
  properties: {
@@ -17,7 +17,7 @@ export class ReactToPostTool extends OperationTool<TReactToPostParams, unknown>
17
17
  return {
18
18
  name: this.name,
19
19
  description:
20
- 'Allows you to react to a post using any available reaction type (st.reactToPost action).',
20
+ 'Allows you to react to a post using any available reaction type (st.reactToPost action). If this workflow is still running, do not retry this tool; retrying can queue duplicate reaction attempts.',
21
21
  inputSchema: {
22
22
  type: 'object',
23
23
  properties: {
@@ -15,7 +15,7 @@ export class RemoveConnectionTool extends OperationTool<TRemoveConnectionParams,
15
15
  return {
16
16
  name: this.name,
17
17
  description:
18
- 'Allows you to remove a person from your connections (st.removeConnection action).',
18
+ 'Allows you to remove a person from your connections (st.removeConnection action). If this workflow is still running, do not retry this tool; retrying can queue duplicate removal attempts for the same person.',
19
19
  inputSchema: {
20
20
  type: 'object',
21
21
  properties: {
@@ -20,7 +20,7 @@ export class SendConnectionRequestTool extends OperationTool<
20
20
  return {
21
21
  name: this.name,
22
22
  description:
23
- 'Allows you to send a connection request to a person (st.sendConnectionRequest action).',
23
+ 'Allows you to send a connection request to a person (st.sendConnectionRequest action). If this workflow is still running, do not retry this tool; retrying can queue duplicate connection request attempts for the same person.',
24
24
  inputSchema: {
25
25
  type: 'object',
26
26
  properties: {
@@ -15,7 +15,8 @@ export class SendMessageTool extends OperationTool<TSendMessageParams, unknown>
15
15
  public override getTool(): Tool {
16
16
  return {
17
17
  name: this.name,
18
- description: 'Allows you to send a message to a person (st.sendMessage action).',
18
+ description:
19
+ 'Allows you to send a message to a person (st.sendMessage action). If this workflow is still running, do not retry this tool; retrying can send duplicate messages to the same person.',
19
20
  inputSchema: {
20
21
  type: 'object',
21
22
  properties: {
@@ -19,7 +19,7 @@ export class WithdrawConnectionRequestTool extends OperationTool<
19
19
  return {
20
20
  name: this.name,
21
21
  description:
22
- 'Allows you to withdraw the connection request sent to a person (st.withdrawConnectionRequest action).',
22
+ 'Allows you to withdraw the connection request sent to a person (st.withdrawConnectionRequest action). If this workflow is still running, do not retry this tool; retrying can queue duplicate withdrawal attempts for the same person.',
23
23
  inputSchema: {
24
24
  type: 'object',
25
25
  properties: {
@@ -0,0 +1,22 @@
1
+ import { LinkedApiAdmin } from '@linkedapi/node';
2
+ import { Tool } from '@modelcontextprotocol/sdk/types.js';
3
+ import z from 'zod';
4
+
5
+ export abstract class AdminTool<TParams, TResult> {
6
+ public abstract readonly name: string;
7
+ protected abstract readonly schema: z.ZodSchema;
8
+
9
+ public abstract getTool(): Tool;
10
+
11
+ public validate(args: unknown): TParams {
12
+ return this.schema.parse(args) as TParams;
13
+ }
14
+
15
+ public abstract execute({
16
+ admin,
17
+ args,
18
+ }: {
19
+ admin: LinkedApiAdmin;
20
+ args: TParams;
21
+ }): Promise<TResult>;
22
+ }
@@ -1,16 +1,28 @@
1
1
  export function defineRequestTimeoutInSeconds(mcpClient: string): number {
2
- const bigTimeout = 600;
2
+ const BIG_TIMEOUT = 600 as const;
3
+ const normalizedMcpClient = mcpClient.trim().toLowerCase();
3
4
 
4
- console.error('mcpClient', mcpClient);
5
- switch (mcpClient) {
5
+ switch (normalizedMcpClient) {
6
+ case 'codex':
7
+ case 'codex-cli':
8
+ case 'codex-desktop':
9
+ case 'openai-codex':
10
+ return BIG_TIMEOUT;
11
+ case 'claude-code':
12
+ case 'claude_code':
13
+ case 'claude code':
14
+ return BIG_TIMEOUT;
6
15
  case 'claude':
16
+ case 'claude-desktop':
17
+ case 'anthropic':
7
18
  return 180;
8
19
  case 'chatgpt':
20
+ case 'openai':
9
21
  return 50;
10
22
  case 'cursor':
11
23
  case 'vscode':
12
24
  case 'windsurf':
13
- return bigTimeout;
25
+ return BIG_TIMEOUT;
14
26
  default:
15
27
  return 60;
16
28
  }