/**
* LinkedIn Get Tool
*/
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { getClient } from "../api/client.js";
// Input Schema
const InputSchema = z.object({
session_id: z.string().describe("Session ID from linkedin_auth"),
type: z.enum(["PROFILE", "COMPANY", "JOB", "GROUP"]).describe("What to get"),
id: z.string().describe("Identifier: username, company slug, job ID, or group ID"),
}).strict();
// Output Schemas
const ExperienceSchema = z.object({
title: z.string().describe("Job title"),
company: z.string().describe("Company name"),
location: z.string().describe("Location"),
description: z.string().describe("Job description"),
});
const EducationSchema = z.object({
school: z.string().describe("School name"),
degree: z.string().describe("Degree name"),
field: z.string().describe("Field of study"),
});
const CertificationSchema = z.object({
name: z.string().describe("Certification name"),
issuer: z.string().describe("Issuing organization"),
});
const ProfileSchema = z.object({
name: z.string().describe("Full name"),
headline: z.string().describe("Professional headline"),
summary: z.string().describe("About/summary section"),
profileUrl: z.string().describe("LinkedIn profile URL"),
publicId: z.string().describe("Public identifier/username"),
experience: z.array(ExperienceSchema).describe("Work experience"),
education: z.array(EducationSchema).describe("Education history"),
skills: z.array(z.string()).describe("Skills list"),
certifications: z.array(CertificationSchema).describe("Certifications"),
});
const CompanySchema = z.object({
name: z.string().describe("Company name"),
tagline: z.string().describe("Company tagline"),
description: z.string().describe("Company description"),
industry: z.string().describe("Industry"),
staffCount: z.number().describe("Number of employees"),
headquarters: z.string().describe("Headquarters location"),
website: z.string().describe("Company website"),
companyUrl: z.string().describe("LinkedIn company URL"),
followerCount: z.number().describe("Number of followers"),
});
const JobSchema = z.object({
title: z.string().describe("Job title"),
company: z.string().describe("Company name"),
location: z.string().describe("Job location"),
employmentType: z.string().describe("Employment type"),
experienceLevel: z.string().describe("Required experience level"),
remote: z.boolean().describe("Whether remote work is allowed"),
salary: z.string().describe("Salary information"),
description: z.string().describe("Job description"),
listedAt: z.string().describe("When job was posted"),
jobUrl: z.string().describe("LinkedIn job URL"),
});
const GroupSchema = z.object({
name: z.string().describe("Group name"),
description: z.string().describe("Group description"),
memberCount: z.number().describe("Number of members"),
type: z.string().describe("Group type"),
groupUrl: z.string().describe("LinkedIn group URL"),
});
const OutputSchema = z.union([ProfileSchema, CompanySchema, JobSchema, GroupSchema]);
const DESCRIPTION = `Get a single LinkedIn item by identifier.
**Types:**
- PROFILE: Get a person's full profile (id = username)
- COMPANY: Get company details (id = company slug)
- JOB: Get job listing (id = job ID from search/URL)
- GROUP: Get group details (id = group ID from URL)
**Examples:**
- Profile: type=PROFILE, id="satyanadella"
- Company: type=COMPANY, id="microsoft"
- Job: type=JOB, id="4322684579"
- Group: type=GROUP, id="2293416"`;
export function registerGetTool(server: McpServer): void {
server.registerTool(
"linkedin_get",
{
title: "LinkedIn Get",
description: DESCRIPTION,
inputSchema: InputSchema,
outputSchema: OutputSchema,
annotations: {
title: "LinkedIn Get Item",
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
},
async (args) => {
try {
const client = getClient(args.session_id);
// PROFILE
if (args.type === "PROFILE") {
const username = args.id.replace(/^\/in\//, "").replace(/\/$/, "");
const profile = await client.getProfile(username);
let output = `# 👤 ${profile.name}\n\n**${profile.headline}**\n\n`;
if (profile.summary) output += `## About\n${profile.summary}\n\n`;
output += `| Field | Value |\n|-------|-------|\n`;
output += `| Name | ${profile.name} |\n`;
output += `| Headline | ${profile.headline} |\n`;
output += `| Profile | ${profile.profileUrl} |\n\n`;
if (profile.experience.length > 0) {
output += `## Experience (${profile.experience.length})\n`;
for (const exp of profile.experience) {
output += `- **${exp.title}** @ ${exp.company}\n`;
if (exp.location) output += ` 📍 ${exp.location}\n`;
}
output += "\n";
}
if (profile.education.length > 0) {
output += `## Education (${profile.education.length})\n`;
for (const edu of profile.education) {
output += `- **${edu.school}** - ${edu.degree}${edu.field ? `, ${edu.field}` : ""}\n`;
}
output += "\n";
}
if (profile.skills.length > 0) {
output += `## Skills (${profile.skills.length})\n${profile.skills.slice(0, 15).join(", ")}\n\n`;
}
if (profile.certifications.length > 0) {
output += `## Certifications (${profile.certifications.length})\n`;
for (const cert of profile.certifications) {
output += `- **${cert.name}** by ${cert.issuer}\n`;
}
}
return { content: [{ type: "text" as const, text: output }], structuredContent: profile };
}
// COMPANY
if (args.type === "COMPANY") {
const slug = args.id.replace(/^\/company\//, "").replace(/\/$/, "");
const company = await client.getCompany(slug);
let output = `# 🏢 ${company.name}\n\n`;
if (company.tagline) output += `*${company.tagline}*\n\n`;
output += `| Field | Value |\n|-------|-------|\n`;
output += `| Name | ${company.name} |\n`;
if (company.industry) output += `| Industry | ${company.industry} |\n`;
if (company.staffCount) output += `| Employees | ${company.staffCount.toLocaleString()} |\n`;
if (company.headquarters) output += `| HQ | ${company.headquarters} |\n`;
if (company.website) output += `| Website | ${company.website} |\n`;
if (company.followerCount) output += `| Followers | ${company.followerCount.toLocaleString()} |\n`;
output += `| LinkedIn | ${company.companyUrl} |\n\n`;
if (company.description) output += `## About\n${company.description}\n`;
return { content: [{ type: "text" as const, text: output }], structuredContent: company };
}
// JOB
if (args.type === "JOB") {
const jobId = args.id.replace(/.*\/jobs\/view\//, "").replace(/\/$/, "");
const job = await client.getJob(jobId);
let output = `# 💼 ${job.title}\n\n**${job.company}**\n\n`;
output += `| Field | Value |\n|-------|-------|\n`;
output += `| Title | ${job.title} |\n`;
output += `| Company | ${job.company} |\n`;
output += `| Location | ${job.location} |\n`;
if (job.employmentType) output += `| Type | ${job.employmentType} |\n`;
if (job.experienceLevel) output += `| Level | ${job.experienceLevel} |\n`;
output += `| Remote | ${job.remote ? "Yes" : "No"} |\n`;
if (job.salary) output += `| Salary | ${job.salary} |\n`;
if (job.listedAt) output += `| Posted | ${job.listedAt.split("T")[0]} |\n`;
output += `| Apply | ${job.jobUrl} |\n\n`;
if (job.description) {
const desc = job.description.length > 2000 ? job.description.substring(0, 2000) + "..." : job.description;
output += `## Description\n${desc}\n`;
}
return { content: [{ type: "text" as const, text: output }], structuredContent: job };
}
// GROUP
if (args.type === "GROUP") {
const groupId = args.id.replace(/.*\/groups\//, "").replace(/\/$/, "");
const group = await client.getGroup(groupId);
let output = `# 👥 ${group.name}\n\n`;
output += `| Field | Value |\n|-------|-------|\n`;
output += `| Name | ${group.name} |\n`;
output += `| Members | ${group.memberCount.toLocaleString()} |\n`;
if (group.type) output += `| Type | ${group.type} |\n`;
output += `| LinkedIn | ${group.groupUrl} |\n\n`;
if (group.description) output += `## Description\n${group.description}\n`;
return { content: [{ type: "text" as const, text: output }], structuredContent: group };
}
return { content: [{ type: "text" as const, text: "Invalid type" }], isError: true };
} catch (error) {
return {
content: [{ type: "text" as const, text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
isError: true,
};
}
}
);
}