diff --git a/package-lock.json b/package-lock.json index b1da9e4..b53a7bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@linkedapi/mcp", - "version": "2.3.17", + "version": "2.3.18", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@linkedapi/mcp", - "version": "2.3.17", + "version": "2.3.18", "license": "MIT", "dependencies": { - "@linkedapi/node": "^2.3.17", + "@linkedapi/node": "^2.3.19", "@modelcontextprotocol/sdk": "^1.17.4", "zod": "^4.1.1" }, @@ -921,9 +921,9 @@ } }, "node_modules/@linkedapi/node": { - "version": "2.3.17", - "resolved": "https://registry.npmjs.org/@linkedapi/node/-/node-2.3.17.tgz", - "integrity": "sha512-2eudeWgD00FTeLjiBzN1Lq/Dwlu68YT4ZmwM3rfb9NlErL/2jeT8dPYvhVApRUGl8ifrmP2pz8rZE/ELHgXgWQ==", + "version": "2.3.19", + "resolved": "https://registry.npmjs.org/@linkedapi/node/-/node-2.3.19.tgz", + "integrity": "sha512-PKLzAK78JxLBGbekmNhvtwVophnkkVP5CVJDo/bPDNwZVMWReAh2rpv76f/B5FcWNmOww+0ZlOHy5PXIEp+rjg==", "license": "MIT" }, "node_modules/@modelcontextprotocol/sdk": { diff --git a/package.json b/package.json index c9334ff..1a3f313 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@linkedapi/mcp", - "version": "2.3.17", + "version": "2.3.18", "description": "MCP server that lets AI assistants control LinkedIn accounts and retrieve real-time data.", "main": "dist/index.js", "bin": { @@ -30,7 +30,7 @@ "author": "Linked API", "license": "MIT", "dependencies": { - "@linkedapi/node": "^2.3.17", + "@linkedapi/node": "^2.3.19", "@modelcontextprotocol/sdk": "^1.17.4", "zod": "^4.1.1" }, diff --git a/src/linked-api-tools.ts b/src/linked-api-tools.ts index 67902c2..c1122d4 100644 --- a/src/linked-api-tools.ts +++ b/src/linked-api-tools.ts @@ -23,6 +23,8 @@ import { CheckConnectionStatusTool } from './tools/check-connection-status.js'; import { CommentOnPostTool } from './tools/comment-on-post.js'; import { CreatePostTool } from './tools/create-post.js'; import { CreateRepostTool } from './tools/create-repost.js'; +import { EndorsePersonSkillTool } from './tools/endorse-person-skill.js'; +import { EndorsePersonSkillsTool } from './tools/endorse-person-skills.js'; import { ExecuteCustomWorkflowTool } from './tools/execute-custom-workflow.js'; import { FetchCompanyTool } from './tools/fetch-company.js'; import { FetchJobTool } from './tools/fetch-job.js'; @@ -114,6 +116,8 @@ export class LinkedApiTools { new SearchPostsTool(), new FetchCompanyTool(), new FetchPersonTool(), + new EndorsePersonSkillTool(), + new EndorsePersonSkillsTool(), new FetchPostTool(), new FetchJobTool(), new ReactToPostTool(), diff --git a/src/tools/admin-delete-limits.ts b/src/tools/admin-delete-limits.ts index 087923b..c9e050f 100644 --- a/src/tools/admin-delete-limits.ts +++ b/src/tools/admin-delete-limits.ts @@ -30,7 +30,7 @@ export class AdminDeleteLimitsTool extends AdminTool return { name: this.name, description: - 'Delete specific rate limits for an account. Deleted limits fall back to system defaults.', + 'Delete specific rate limits for an account. Each removed category/period has no limit until set again. Use admin_reset_limits to restore all default limits for the account.', inputSchema: { type: 'object', properties: { @@ -46,7 +46,7 @@ export class AdminDeleteLimitsTool extends AdminTool properties: { category: { type: 'string', - description: 'Limit category', + description: 'Limit category, e.g. stEndorsements', }, period: { type: 'string', diff --git a/src/tools/admin-set-limits.ts b/src/tools/admin-set-limits.ts index e89dd18..6d44634 100644 --- a/src/tools/admin-set-limits.ts +++ b/src/tools/admin-set-limits.ts @@ -32,7 +32,7 @@ export class AdminSetLimitsTool extends AdminTool { return { name: this.name, description: - '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.', + '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, stEndorsements, nvPersonProfileViews, nvCompanyPageViews, nvMessages.', inputSchema: { type: 'object', properties: { diff --git a/src/tools/endorse-person-skill.ts b/src/tools/endorse-person-skill.ts new file mode 100644 index 0000000..205b4f6 --- /dev/null +++ b/src/tools/endorse-person-skill.ts @@ -0,0 +1,39 @@ +import { OPERATION_NAME, TEndorsePersonSkillParams } from '@linkedapi/node'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { z } from 'zod'; + +import { OperationTool } from '../utils/linked-api-tool.js'; + +export class EndorsePersonSkillTool extends OperationTool { + public override readonly name = 'endorse_person_skill'; + public override readonly operationName = OPERATION_NAME.endorsePersonSkill; + protected override readonly schema = z.object({ + personUrl: z.string(), + skillName: z.string().min(1).max(200), + }); + + public override getTool(): Tool { + return { + name: this.name, + description: + "Endorses one skill by name on a 1st-degree connection's profile. Skill names are in the profile owner's language, regardless of your LinkedIn language. An already-endorsed skill counts as success and is never removed. Every success, including an existing endorsement, counts toward the stEndorsements limit. Use endorse_person_skills to select skills with patterns or endorse all skills. If this workflow is still running, do not retry this tool; retrying can count the same skill toward the stEndorsements limit again.", + inputSchema: { + type: 'object', + properties: { + personUrl: { + type: 'string', + description: 'Public or hashed LinkedIn URL of your 1st-degree connection.', + }, + skillName: { + type: 'string', + minLength: 1, + maxLength: 200, + description: + "Exact skill name in the profile owner's language, up to 200 characters. Letter case and extra spaces are ignored. This is not a pattern.", + }, + }, + required: ['personUrl', 'skillName'], + }, + }; + } +} diff --git a/src/tools/endorse-person-skills.ts b/src/tools/endorse-person-skills.ts new file mode 100644 index 0000000..8e76c91 --- /dev/null +++ b/src/tools/endorse-person-skills.ts @@ -0,0 +1,51 @@ +import { + OPERATION_NAME, + TEndorsePersonSkillsParams, + TPersonSkillEndorsement, +} from '@linkedapi/node'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { z } from 'zod'; + +import { OperationTool } from '../utils/linked-api-tool.js'; + +export class EndorsePersonSkillsTool extends OperationTool< + TEndorsePersonSkillsParams, + Array +> { + public override readonly name = 'endorse_person_skills'; + public override readonly operationName = OPERATION_NAME.endorsePersonSkills; + protected override readonly schema = z.object({ + personUrl: z.string(), + skillNamePatterns: z.array(z.string().min(1).max(200)).min(1).max(20).optional(), + }); + + public override getTool(): Tool { + return { + name: this.name, + description: + "Endorses selected skills of a 1st-degree connection, returning each selected skill's name, success and error if it failed. Skill names are in the profile owner's language. Patterns use RE2, are case-insensitive and match anywhere; anchor with ^…$ to match a whole name. Omit skillNamePatterns to endorse all skills; never pass []. An already-endorsed skill counts as success and is never removed. Each success counts toward the stEndorsements limit, including existing endorsements. The limit is checked for each skill; a failure does not stop the others, so check every item's success. If this workflow is still running, do not retry this tool; retrying can count the same skills toward the stEndorsements limit again.", + inputSchema: { + type: 'object', + properties: { + personUrl: { + type: 'string', + description: 'Public or hashed LinkedIn URL of your 1st-degree connection.', + }, + skillNamePatterns: { + type: 'array', + minItems: 1, + maxItems: 20, + items: { + type: 'string', + minLength: 1, + maxLength: 200, + }, + description: + "Optional. 1-20 RE2 patterns, each 1-200 characters, matching names in the profile owner's language. Any matching pattern selects the skill. Matching is case-insensitive and searches anywhere: manage matches Project Management; ^scrum$ matches only the whole name Scrum. Lookaround and backreferences are unsupported. Omit this parameter to endorse all skills; never pass an empty array.", + }, + }, + required: ['personUrl'], + }, + }; + } +}