Candidate MCP Server Library

by jhgaylor

81 335 downloads Not rated yet MIT

About

A Model Context Protocol (MCP) server library that gives LLMs access to information about a candidate.

Details

License
MIT

Explore

- Library-first design for integration into other applications
- Modular resource system for extending with custom candidate information
- TypeScript for type safety and better developer experience
- Implements the full Model Context Protocol specification
- Supports multiple transport types (STDIO, HTTP, Streamable HTTP)
- Minimal dependencies

npm install @jhgaylor/candidate-mcp-server

This package is designed to be imported and used within your own applications.

npm install

Once integrated into your application, clients can interact with the MCP server by sending JSON-RPC requests. Here are examples of requests that your application would handle after integrating this library:

get_resume_text

Returns the candidate's resume content as text

get_resume_url

Returns the URL to the candidate's resume

get_linkedin_url

Returns the candidate's LinkedIn profile URL

get_github_url

Returns the candidate's GitHub profile URL

get_website_url

Returns the candidate's personal website URL

get_website_text

Returns the content from the candidate's personal website

contact_candidate

Sends an email to the candidate (requires Mailgun configuration)

This MCP server also provides tools that return the same candidate information:

- get_resume_text: Returns the candidate's resume content as text
- get_resume_url: Returns the URL to the candidate's resume
- get_linkedin_url: Returns the candidate's LinkedIn profile URL
- get_github_url: Returns the candidate's GitHub profile URL
- get_website_url: Returns the candidate's personal website URL
- get_website_text: Returns the content from the candidate's personal website
- contact_candidate: Sends an email to the candidate (requires Mailgun configuration)

A Model Context Protocol (MCP) server that gives LLMs access to information about a candidate.

Overview

> Important: This server is intended to be used as a library to be integrated into other applications, not as a standalone service. The provided startup methods are for demonstration and testing purposes only.

Resources

This MCP server provides the following resources:

- candidate-info://resume-text: Resume content as text
- candidate-info://resume-url: URL to the resume
- candidate-info://linkedin-url: LinkedIn profile URL
- candidate-info://github-url: GitHub profile URL
- candidate-info://website-url: Personal website URL
- candidate-info://website-text: Content from the personal website

Tools

This MCP server also provides tools that return the same candidate information:

- get_resume_text: Returns the candidate's resume content as text
- get_resume_url: Returns the URL to the candidate's resume
- get_linkedin_url: Returns the candidate's LinkedIn profile URL
- get_github_url: Returns the candidate's GitHub profile URL
- get_website_url: Returns the candidate's personal website URL
- get_website_text: Returns the content from the candidate's personal website
- contact_candidate: Sends an email to the candidate (requires Mailgun configuration)

Usage

npm install @jhgaylor/candidate-mcp-server

Library Usage

This package is designed to be imported and used within your own applications.

Stdio

Starting the process is a breeze with stdio. The interesting part is providing the candidate configuration.

Where you source the candidate configuration is entirely up to you. Maybe you hard code it. Maybe you take a JSONResume url when you start the process. It's up to you!

import { createServer } from '@jhgaylor/candidate-mcp-server';
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

// Configure your server
const serverConfig = {
name: "MyCandidateServer",
version: "1.0.0",
mailgunApiKey: process.env.MAILGUN_API_KEY,
mailgunDomain: process.env.MAILGUN_DOMAIN
};
const candidateConfig = {
name: "John Doe",
email: "[email protected]", // Required for the contact_candidate tool
resumeUrl: "https://example.com/resume.pdf",
// other candidate properties
};

// Create server instance
const server = createServer(serverConfig, candidateConfig);

// Connect with your preferred transport
await server.connect(new StdioServerTransport());
// or integrate with your existing HTTP server

StreamableHttp

Using the example code provided by the typescript sdk we can bind this mcp server to an express server.

import express from 'express';
import { Request, Response } from 'express';
import { createServer } from '@jhgaylor/candidate-mcp-server';
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamablehttp.js";

// Configure your server
const serverConfig = {
name: "MyCandidateServer",
version: "1.0.0",
mailgunApiKey: process.env.MAILGUN_API_KEY,
mailgunDomain: process.env.MAILGUN_DOMAIN,
contactEmail: "[email protected]",
};
const candidateConfig = {
name: "John Doe",
resumeUrl: "https://example.com/resume.pdf",
// other candidate properties
};

// Factory function to create a new server instance for each request
const getServer = () => createServer(serverConfig, candidateConfig);

const app = express();
app.use(express.json());

app.post('/mcp', async (req: Request, res: Response) => {
// In stateless mode, create a new instance of transport and server for each request
// to ensure complete isolation. A single instance would cause request ID collisions
// when multiple clients connect concurrently.

try {
const server = getServer();
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
res.on('close', () => {
console.log('Request closed');
transport.close();
server.close();
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});

app.get('/mcp', async (req: Request, res: Response) => {
console.log('Received GET MCP request');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "Method not allowed."
},
id: null
}));
});

app.delete('/mcp', async (req: Request, res: Response) => {
console.log('Received DELETE MCP request');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "Method not allowed."
},
id: null
}));
});

// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(MCP Stateless Streamable HTTP Server listening on port ${PORT});
});

Express

Instead of writing the binding between express and the mcp transport yourself, you can use express-mcp-handler to do it for you.

npm install express-mcp-handler

import express from 'express';
import { statelessHandler } from 'express-mcp-handler';
import { createServer } from './server';

// You can configure the server factory to include Mailgun settings
const createServerWithConfig = () => {
const serverConfig = {
name: "MyCandidateServer",
version: "1.0.0",
mailgunApiKey: process.env.MAILGUN_API_KEY,
mailgunDomain: process.env.MAILGUN_DOMAIN,
contactEmail: "[email protected]",
};
const candidateConfig = {
name: "John Doe",
resumeUrl: "https://example.com/resume.pdf",
// other candidate properties
};

return createServer(serverConfig, candidateConfig);
};

// Configure the stateless handler
const handler = statelessHandler(createServerWithConfig);

// Create Express app
const app = express();
app.use(express.json());

// Mount the handler (stateless only needs POST)
app.post('/mcp', handler);

// Start the server
const PORT = process.env.PORT || 3002;
app.listen(PORT, () => {
console.log(Stateless MCP server running on port ${PORT});
});

Development

```bash

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.