一个模型上下文协议(MCP)服务器,提供LLMs访问候选人信息的功能。
重要提示:此服务器旨在作为库集成到其他应用程序中,而不是作为一个独立的服务。提供的启动方法仅用于演示和测试目的。
此MCP服务器提供以下资源:
candidate-info://resume-text:简历内容作为文本candidate-info://resume-url:简历的URLcandidate-info://linkedin-url:LinkedIn个人资料URLcandidate-info://github-url:GitHub个人资料URLcandidate-info://website-url:个人网站URLcandidate-info://website-text:个人网站的内容此MCP服务器还提供了返回相同候选人信息的工具:
get_resume_text:返回候选人的简历内容作为文本get_resume_url:返回候选人的简历URLget_linkedin_url:返回候选人的LinkedIn个人资料URLget_github_url:返回候选人的GitHub个人资料URLget_website_url:返回候选人的个人网站URLget_website_text:返回候选人的个人网站内容contact_candidate:向候选人发送电子邮件(需要Mailgun配置)npm install @jhgaylor/candidate-mcp-server
此包设计为在您自己的应用程序中导入并使用。
使用标准I/O启动进程非常简单。有趣的部分是提供候选人配置。
您从何处获取候选人配置完全取决于您。也许您硬编码它。也许您在启动进程时提供一个JSONResume URL。这由您决定!
import { createServer } from '@jhgaylor/candidate-mcp-server';
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// 配置您的服务器
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: "john.doe@example.com", // 对于contact_candidate工具是必需的
resumeUrl: "https://example.com/resume.pdf",
// 其他候选人属性
};
// 创建服务器实例
const server = createServer(serverConfig, candidateConfig);
// 使用您首选的传输连接
await server.connect(new StdioServerTransport());
// 或者与现有的HTTP服务器集成
使用类型脚本SDK提供的示例代码,我们可以将此MCP服务器绑定到一个Express服务器。
import express from 'express';
import { Request, Response } from 'express';
import { createServer } from '@jhgaylor/candidate-mcp-server';
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamablehttp.js";
// 配置您的服务器
const serverConfig = {
name: "MyCandidateServer",
version: 1.0.0,
mailgunApiKey: process.env.MAILGUN_API_KEY,
mailgunDomain: process.env.MAILGUN_DOMAIN,
contactEmail: "john.doe@example.com",
};
const candidateConfig = {
name: "John Doe",
resumeUrl: "https://example.com/resume.pdf",
// 其他候选人属性
};
// 工厂函数,为每个请求创建一个新的服务器实例
const getServer = () => createServer(serverConfig, candidateConfig);
const app = express();
app.use(express.json());
app.post('/mcp', async (req: Request, res: Response) => {
// 在无状态模式下,为每个请求创建一个新的传输和服务器实例
// 以确保完全隔离。单个实例会在多个客户端同时连接时导致请求ID冲突。
try {
const server = getServer();
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
res.on('close', () => {
console.log('请求已关闭');
transport.close();
server.close();
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error('处理MCP请求时出错:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: '内部服务器错误',
},
id: null,
});
}
}
});
app.get('/mcp', async (req: Request, res: Response) => {
console.log('收到GET MCP请求');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "不允许的方法。",
},
id: null
}));
});
app.delete('/mcp', async (req: Request, res: Response) => {
console.log('收到DELETE MCP请求');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "不允许的方法。",
},
id: null
}));
});
// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`MCP无状态可流式HTTP服务器正在端口${PORT}上监听`);
});
您可以使用express-mcp-handler来代替自己编写Express和MCP传输之间的绑定。
npm install express-mcp-handler
import express from 'express';
import { statelessHandler } from 'express-mcp-handler';
import { createServer } from './server';
// 您可以配置服务器工厂以包括Mailgun设置
const createServerWithConfig = () => {
const serverConfig = {
name: "MyCandidateServer",
version: "1.0.0",
mailgunApiKey: process.env.MAILGUN_API_KEY,
mailgunDomain: process.env.MAILGUN_DOMAIN,
contactEmail: "john.doe@example.com",
};
const candidateConfig = {
name: "John Doe",
resumeUrl: "https://example.com/resume.pdf",
// 其他候选人属性
};
return createServer(serverConfig, candidateConfig);
};
// 配置无状态处理器
const handler = statelessHandler(createServerWithConfig);
// 创建Express应用
const app = express();
app.use(express.json());
// 安装处理器(无状态只需要POST)
app.post('/mcp', handler);
// 启动服务器
const PORT = process.env.PORT || 3002;
app.listen(PORT, () => {
console.log(`无状态MCP服务器正在端口${PORT}上运行`);
});
# 安装依赖
npm install
# 构建项目
npm run build
# 在开发模式下运行并自动重启
npm run dev
# 通过标准I/O启动(仅限演示)
npm start
当使用标准I/O运行时,可以通过发送MCP消息(作为单行JSON对象)与服务器交互:
# 发送初始化消息的示例
echo '{"jsonrpc": "2.0","id": 1,"method": "initialize","params": {"protocolVersion": "2024-11-05","capabilities": {"roots": {"listChanged": true},"sampling": {}},"clientInfo": {"name": "ExampleClient","version": "1.0.0"}}}' | node dist/index.js --stdio
# 列出资源
echo '{"jsonrpc": "2.0","id": 2,"method": "resources/list","params": {}}' | node dist/index.js --stdio
# 访问资源
echo '{"jsonrpc": "2.0","id": 3,"method": "resources/read","params": {"uri": "candidate-info://resume-text"}}' | node dist/index.js --stdio
# 列出工具
echo '{"jsonrpc": "2.0","id": 2,"method": "tools/list","params": {}}' | node dist/index.js --stdio
# 调用工具
echo '{"jsonrpc": "2.0","id": 4,"method": "tools/call","params": {"name": "get_resume_text", "args": {}}}' | node dist/index.js --stdio
# 向候选人发送电子邮件
echo '{"jsonrpc": "2.0","id": 5,"method": "tools/call","params": {"name": "contact_candidate", "args": {"subject": "Hello from AI!", "message": "This is a test email sent via the MCP server.", "reply_address": "recruiter@company.com"}}}' | node dist/index.js --stdio
每条消息必须在一行内,JSON对象内不能有换行符。
src/
├── index.ts # 主包入口点
├── server.ts # 带有配置的MCP服务器工厂
├── config.ts # 配置类型定义
└── resources/ # 模块化资源定义
└── index.ts # 资源工厂和实现
此库实现了模型上下文协议(MCP),这是一种标准化的方式,使LLMs能够与外部数据和功能交互。将其集成到您的应用程序中后,它会暴露一个无状态API,响应JSON-RPC请求。
一旦集成到您的应用程序中,客户端可以通过发送JSON-RPC请求与MCP服务器交互。以下是集成此库后您的应用程序将处理的一些请求示例:
curl -X POST http://your-application-url/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Accept: text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {}
},
"clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
}
}
}'
curl -X POST http://your-application-url/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Accept: text/event-stream" \
-d '{
"jsonrpc": "2.0",
"method": "resources/read",
"params": {
"uri": "candidate-info://resume-text"
},
"id": 2
}'
此库设计为可以扩展自定义资源、工具和提示。这里是如何添加您自己的资源:
import { McpServer, Resource } from '@jhgaylor/candidate-mcp-server';
// 创建您的自定义资源类
class CustomCandidateResource extends Resource {
constructor(candidateConfig) {
super(
`${candidateConfig.name} 自定义数据`,
"candidate-info://custom-data",
async () => {
return {
contents: [
{
uri: "candidate-info://custom-data",
mimeType: "text/plain",
text: "您的自定义候选人数据在这里"
}
]
};
}
);
}
}
// 使用标准配置创建服务器
const server = createServer(serverConfig, candidateConfig);
// 添加您的自定义资源
const customResource = new CustomCandidateResource(candidateConfig);
customResource.bind(server);
// 使用您首选的传输连接
// ...
您还可以通过自定义工具扩展库:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { createServer } from '@jhgaylor/candidate-mcp-server';
// 使用标准配置创建服务器
const server = createServer(serverConfig, candidateConfig);
// 添加一个自定义工具
server.tool(
'get_candidate_skills',
'返回候选人的技能列表',
{},
async (_args, _extra) => {
return {
content: [
{
type: "text",
text: "JavaScript, TypeScript, React, Node.js, MCP协议"
}
]
};
}
);
// 使用您首选的传输连接
// ...
如果您尚未登录,请先登录npm:
npm login
发布包到npm(将运行您的预发布构建):
npm publish
要增加版本号、打标签并推送新版本:
npm version patch # 或minor,major
git push origin main --tags