llmconveyors-mcp 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +232 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +808 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LLM Conveyors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# llmconveyors-mcp
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/llmconveyors-mcp)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
|
|
7
|
+
MCP server that connects AI agents to the [LLM Conveyors](https://llmconveyors.com) platform — run Job Hunter, B2B Sales, and other AI agents directly from Claude, Cursor, or any MCP-compatible client.
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<img src="https://llmconveyors.com/assets/logo.png" alt="LLM Conveyors" width="200" />
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
## What is LLM Conveyors?
|
|
14
|
+
|
|
15
|
+
A community-driven AI agent platform with pay-per-action pricing ($1–5 per completed action). Instead of $100/mo SaaS subscriptions, you pay only for real outputs — a resume scored, a company researched, a cold email generated.
|
|
16
|
+
|
|
17
|
+
**Live Agents:**
|
|
18
|
+
- **Job Hunter** — Tailored CVs, cover letters, and cold emails for job applications
|
|
19
|
+
- **B2B Sales** — Deep company research and personalized sales outreach
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### 1. Get an API key
|
|
24
|
+
|
|
25
|
+
Sign up at [llmconveyors.com](https://llmconveyors.com) and create an API key from Settings → API Keys.
|
|
26
|
+
|
|
27
|
+
### 2. Add to your MCP client
|
|
28
|
+
|
|
29
|
+
<details>
|
|
30
|
+
<summary><strong>Claude Desktop</strong></summary>
|
|
31
|
+
|
|
32
|
+
Add to `claude_desktop_config.json`:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"llmconveyors": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "llmconveyors-mcp"],
|
|
40
|
+
"env": {
|
|
41
|
+
"LLMC_API_KEY": "llmc_your_key_here"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<details>
|
|
50
|
+
<summary><strong>Claude Code</strong></summary>
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
claude mcp add llmconveyors -- npx -y llmconveyors-mcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Set the env var in your shell or `.env`:
|
|
57
|
+
```bash
|
|
58
|
+
export LLMC_API_KEY=llmc_your_key_here
|
|
59
|
+
```
|
|
60
|
+
</details>
|
|
61
|
+
|
|
62
|
+
<details>
|
|
63
|
+
<summary><strong>Cursor</strong></summary>
|
|
64
|
+
|
|
65
|
+
Add to `.cursor/mcp.json`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"mcpServers": {
|
|
70
|
+
"llmconveyors": {
|
|
71
|
+
"command": "npx",
|
|
72
|
+
"args": ["-y", "llmconveyors-mcp"],
|
|
73
|
+
"env": {
|
|
74
|
+
"LLMC_API_KEY": "llmc_your_key_here"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
</details>
|
|
81
|
+
|
|
82
|
+
<details>
|
|
83
|
+
<summary><strong>Windsurf</strong></summary>
|
|
84
|
+
|
|
85
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"llmconveyors": {
|
|
91
|
+
"command": "npx",
|
|
92
|
+
"args": ["-y", "llmconveyors-mcp"],
|
|
93
|
+
"env": {
|
|
94
|
+
"LLMC_API_KEY": "llmc_your_key_here"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
</details>
|
|
101
|
+
|
|
102
|
+
### 3. Start using it
|
|
103
|
+
|
|
104
|
+
Ask your AI agent:
|
|
105
|
+
|
|
106
|
+
> "Run the Job Hunter agent for the Senior Engineer role at Anthropic. Here's the job description: ..."
|
|
107
|
+
|
|
108
|
+
> "Score my resume against this job posting for ATS compatibility."
|
|
109
|
+
|
|
110
|
+
> "Research Stripe and draft a B2B cold email for our developer tools product."
|
|
111
|
+
|
|
112
|
+
## Available Tools (39)
|
|
113
|
+
|
|
114
|
+
### Agents
|
|
115
|
+
| Tool | Description |
|
|
116
|
+
|------|-------------|
|
|
117
|
+
| `job-hunter-run` | Run the Job Hunter agent — generates tailored CV, cover letter, and cold email |
|
|
118
|
+
| `b2b-sales-run` | Run the B2B Sales agent — researches a company and generates sales outreach |
|
|
119
|
+
| `agent-status` | Check the status of a running agent job |
|
|
120
|
+
| `agent-manifest` | Get input fields, capabilities, and billing info for an agent |
|
|
121
|
+
|
|
122
|
+
### Resume
|
|
123
|
+
| Tool | Description |
|
|
124
|
+
|------|-------------|
|
|
125
|
+
| `resume-validate` | Validate a resume in JSON Resume format |
|
|
126
|
+
| `resume-render` | Render a resume to PDF |
|
|
127
|
+
| `resume-preview` | Preview a resume as HTML |
|
|
128
|
+
| `resume-themes` | List available resume themes |
|
|
129
|
+
| `resume-import-rx` | Import from Reactive Resume format |
|
|
130
|
+
| `resume-export-rx` | Export to Reactive Resume format |
|
|
131
|
+
|
|
132
|
+
### Master Resumes
|
|
133
|
+
| Tool | Description |
|
|
134
|
+
|------|-------------|
|
|
135
|
+
| `master-resume-create` | Create a new master resume |
|
|
136
|
+
| `master-resume-list` | List all master resumes |
|
|
137
|
+
| `master-resume-get` | Get a master resume by ID |
|
|
138
|
+
| `master-resume-update` | Update a master resume |
|
|
139
|
+
| `master-resume-delete` | Delete a master resume |
|
|
140
|
+
|
|
141
|
+
### Upload & Parse
|
|
142
|
+
| Tool | Description |
|
|
143
|
+
|------|-------------|
|
|
144
|
+
| `upload-resume` | Upload and parse a resume file (base64) |
|
|
145
|
+
| `upload-job-file` | Upload and parse a job description file (base64) |
|
|
146
|
+
| `upload-job-text` | Parse a job description from plain text |
|
|
147
|
+
|
|
148
|
+
### ATS Scoring
|
|
149
|
+
| Tool | Description |
|
|
150
|
+
|------|-------------|
|
|
151
|
+
| `ats-score` | Score a resume against a job description for ATS compatibility |
|
|
152
|
+
|
|
153
|
+
### Sessions
|
|
154
|
+
| Tool | Description |
|
|
155
|
+
|------|-------------|
|
|
156
|
+
| `session-create` | Create a new session |
|
|
157
|
+
| `session-list` | List sessions with optional filtering |
|
|
158
|
+
| `session-get` | Get a session by ID |
|
|
159
|
+
| `session-hydrate` | Get full session with artifacts and logs |
|
|
160
|
+
| `session-delete` | Delete a session |
|
|
161
|
+
|
|
162
|
+
### Settings & API Keys
|
|
163
|
+
| Tool | Description |
|
|
164
|
+
|------|-------------|
|
|
165
|
+
| `settings-profile` | Get user profile (credits, plan) |
|
|
166
|
+
| `settings-preferences-get` | Get user preferences |
|
|
167
|
+
| `settings-preferences-update` | Update user preferences |
|
|
168
|
+
| `settings-usage-summary` | Get usage summary |
|
|
169
|
+
| `settings-usage-logs` | Get paginated usage logs |
|
|
170
|
+
| `api-key-create` | Create a new API key |
|
|
171
|
+
| `api-key-list` | List all API keys |
|
|
172
|
+
| `api-key-revoke` | Revoke an API key |
|
|
173
|
+
| `api-key-rotate` | Rotate an API key |
|
|
174
|
+
|
|
175
|
+
### Content & Sharing
|
|
176
|
+
| Tool | Description |
|
|
177
|
+
|------|-------------|
|
|
178
|
+
| `content-save` | Save a source document for AI generation context |
|
|
179
|
+
| `content-delete-generation` | Delete a generation and its artifacts |
|
|
180
|
+
| `share-create` | Create a public share link for generated content |
|
|
181
|
+
| `share-stats` | Get share link statistics |
|
|
182
|
+
| `share-get-public` | Get a public share by slug |
|
|
183
|
+
|
|
184
|
+
### Documents
|
|
185
|
+
| Tool | Description |
|
|
186
|
+
|------|-------------|
|
|
187
|
+
| `document-download` | Download an artifact by storage path |
|
|
188
|
+
|
|
189
|
+
## API Key Scopes
|
|
190
|
+
|
|
191
|
+
Your API key needs the right scopes for the tools you want to use:
|
|
192
|
+
|
|
193
|
+
| Scope | Tools |
|
|
194
|
+
|-------|-------|
|
|
195
|
+
| `jobs:read` | `agent-status`, `agent-manifest` |
|
|
196
|
+
| `jobs:write` | `job-hunter-run` |
|
|
197
|
+
| `sales:write` | `b2b-sales-run` |
|
|
198
|
+
| `sessions:read` | `session-list`, `session-get`, `session-hydrate` |
|
|
199
|
+
| `sessions:write` | `session-create`, `session-delete` |
|
|
200
|
+
| `resume:read` | `resume-themes`, `master-resume-list`, `master-resume-get` |
|
|
201
|
+
| `resume:write` | `resume-validate`, `resume-render`, `resume-preview`, `resume-import-rx`, `resume-export-rx`, `master-resume-create`, `master-resume-update`, `master-resume-delete` |
|
|
202
|
+
| `upload:write` | `upload-resume`, `upload-job-file`, `upload-job-text` |
|
|
203
|
+
| `ats:write` | `ats-score` |
|
|
204
|
+
| `settings:read` | `settings-profile`, `settings-preferences-get`, `settings-usage-summary`, `settings-usage-logs`, `api-key-list` |
|
|
205
|
+
| `settings:write` | `settings-preferences-update`, `api-key-create`, `api-key-revoke`, `api-key-rotate` |
|
|
206
|
+
|
|
207
|
+
## Development
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
git clone https://github.com/llmconveyors/llmconveyors-mcp.git
|
|
211
|
+
cd llmconveyors-mcp
|
|
212
|
+
npm install
|
|
213
|
+
npm run build
|
|
214
|
+
|
|
215
|
+
# Test locally
|
|
216
|
+
LLMC_API_KEY=llmc_your_key node dist/index.js
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Requirements
|
|
220
|
+
|
|
221
|
+
- Node.js >= 18
|
|
222
|
+
- An LLM Conveyors API key ([get one here](https://llmconveyors.com))
|
|
223
|
+
|
|
224
|
+
## Links
|
|
225
|
+
|
|
226
|
+
- [LLM Conveyors Platform](https://llmconveyors.com)
|
|
227
|
+
- [API Documentation](https://llmconveyors.com/docs/api)
|
|
228
|
+
- [TypeScript SDK](https://www.npmjs.com/package/llmconveyors)
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT — see [LICENSE](LICENSE) for details.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { LLMConveyors } from "llmconveyors";
|
|
7
|
+
|
|
8
|
+
// src/tools/agents.ts
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
function registerAgentTools(server2, client2) {
|
|
11
|
+
server2.tool(
|
|
12
|
+
"job-hunter-run",
|
|
13
|
+
"Run the Job Hunter agent \u2014 generates a tailored CV, cover letter, and cold email for a job application. Returns artifacts when complete.",
|
|
14
|
+
{
|
|
15
|
+
companyName: z.string().describe("Target company name"),
|
|
16
|
+
jobTitle: z.string().describe("Job title to apply for"),
|
|
17
|
+
jobDescription: z.string().describe("Full job description text"),
|
|
18
|
+
masterResumeId: z.string().optional().describe("ID of a stored master resume to use"),
|
|
19
|
+
theme: z.string().optional().describe("Resume theme (Even, StackOverflow, Class, Professional)"),
|
|
20
|
+
contactName: z.string().optional().describe("Hiring manager or recruiter name"),
|
|
21
|
+
contactEmail: z.string().optional().describe("Contact email for cold outreach"),
|
|
22
|
+
mode: z.enum(["standard", "cold_outreach"]).optional().describe("Generation mode")
|
|
23
|
+
},
|
|
24
|
+
async (params) => {
|
|
25
|
+
try {
|
|
26
|
+
const result = await client2.agents.run("job-hunter", {
|
|
27
|
+
companyName: params.companyName,
|
|
28
|
+
jobTitle: params.jobTitle,
|
|
29
|
+
jobDescription: params.jobDescription,
|
|
30
|
+
masterResumeId: params.masterResumeId,
|
|
31
|
+
theme: params.theme,
|
|
32
|
+
contactName: params.contactName,
|
|
33
|
+
contactEmail: params.contactEmail,
|
|
34
|
+
mode: params.mode
|
|
35
|
+
});
|
|
36
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
37
|
+
} catch (err) {
|
|
38
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
server2.tool(
|
|
44
|
+
"b2b-sales-run",
|
|
45
|
+
"Run the B2B Sales agent \u2014 researches a company and generates personalized sales outreach.",
|
|
46
|
+
{
|
|
47
|
+
companyName: z.string().describe("Target company name"),
|
|
48
|
+
companyWebsite: z.string().describe("Target company website URL"),
|
|
49
|
+
strategy: z.string().optional().describe("Sales strategy or approach")
|
|
50
|
+
},
|
|
51
|
+
async (params) => {
|
|
52
|
+
try {
|
|
53
|
+
const result = await client2.agents.run("b2b-sales", {
|
|
54
|
+
companyName: params.companyName,
|
|
55
|
+
companyWebsite: params.companyWebsite,
|
|
56
|
+
strategy: params.strategy
|
|
57
|
+
});
|
|
58
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
59
|
+
} catch (err) {
|
|
60
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
61
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
server2.tool(
|
|
66
|
+
"agent-status",
|
|
67
|
+
"Check the status of a running agent job.",
|
|
68
|
+
{
|
|
69
|
+
agentType: z.enum(["job-hunter", "b2b-sales"]).describe("Agent type"),
|
|
70
|
+
jobId: z.string().describe("Job ID returned from a generate call")
|
|
71
|
+
},
|
|
72
|
+
async (params) => {
|
|
73
|
+
try {
|
|
74
|
+
const result = await client2.agents.getStatus(params.agentType, params.jobId, {
|
|
75
|
+
include: ["logs", "artifacts"]
|
|
76
|
+
});
|
|
77
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
78
|
+
} catch (err) {
|
|
79
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
80
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
server2.tool(
|
|
85
|
+
"agent-manifest",
|
|
86
|
+
"Get the manifest (input fields, capabilities, billing) for an agent type.",
|
|
87
|
+
{
|
|
88
|
+
agentType: z.enum(["job-hunter", "b2b-sales"]).describe("Agent type")
|
|
89
|
+
},
|
|
90
|
+
async (params) => {
|
|
91
|
+
try {
|
|
92
|
+
const result = await client2.agents.getManifest(params.agentType);
|
|
93
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
94
|
+
} catch (err) {
|
|
95
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
96
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/tools/ats.ts
|
|
103
|
+
import { z as z2 } from "zod";
|
|
104
|
+
function registerAtsTools(server2, client2) {
|
|
105
|
+
server2.tool(
|
|
106
|
+
"ats-score",
|
|
107
|
+
"Score a resume against a job description for ATS compatibility. Returns overall score, grade, keyword matches, and improvement suggestions.",
|
|
108
|
+
{
|
|
109
|
+
resumeText: z2.string().describe("Resume as plain text"),
|
|
110
|
+
jobDescription: z2.string().describe("Job description as plain text")
|
|
111
|
+
},
|
|
112
|
+
async (params) => {
|
|
113
|
+
try {
|
|
114
|
+
const result = await client2.ats.score({
|
|
115
|
+
resumeText: params.resumeText,
|
|
116
|
+
jobDescription: params.jobDescription
|
|
117
|
+
});
|
|
118
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
119
|
+
} catch (err) {
|
|
120
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
121
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/tools/resume.ts
|
|
128
|
+
import { z as z3 } from "zod";
|
|
129
|
+
function registerResumeTools(server2, client2) {
|
|
130
|
+
server2.tool(
|
|
131
|
+
"resume-validate",
|
|
132
|
+
"Validate a resume in JSON Resume format. Returns validation errors and warnings.",
|
|
133
|
+
{
|
|
134
|
+
resume: z3.record(z3.unknown()).describe("Resume object in JSON Resume format")
|
|
135
|
+
},
|
|
136
|
+
async (params) => {
|
|
137
|
+
try {
|
|
138
|
+
const result = await client2.resume.validate({ resume: params.resume });
|
|
139
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
140
|
+
} catch (err) {
|
|
141
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
142
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
server2.tool(
|
|
147
|
+
"resume-render",
|
|
148
|
+
"Render a resume to PDF. Returns a URL to download the generated PDF.",
|
|
149
|
+
{
|
|
150
|
+
resume: z3.record(z3.unknown()).describe("Resume object in JSON Resume format"),
|
|
151
|
+
theme: z3.string().optional().describe("Theme name (e.g. Even, StackOverflow, Class, Professional)"),
|
|
152
|
+
format: z3.string().optional().describe("Output format")
|
|
153
|
+
},
|
|
154
|
+
async (params) => {
|
|
155
|
+
try {
|
|
156
|
+
const result = await client2.resume.render({
|
|
157
|
+
resume: params.resume,
|
|
158
|
+
theme: params.theme,
|
|
159
|
+
format: params.format
|
|
160
|
+
});
|
|
161
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
162
|
+
} catch (err) {
|
|
163
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
164
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
server2.tool(
|
|
169
|
+
"resume-preview",
|
|
170
|
+
"Preview a resume as HTML. Returns rendered HTML string.",
|
|
171
|
+
{
|
|
172
|
+
resume: z3.record(z3.unknown()).describe("Resume object in JSON Resume format"),
|
|
173
|
+
theme: z3.string().optional().describe("Theme name")
|
|
174
|
+
},
|
|
175
|
+
async (params) => {
|
|
176
|
+
try {
|
|
177
|
+
const result = await client2.resume.preview({
|
|
178
|
+
resume: params.resume,
|
|
179
|
+
theme: params.theme
|
|
180
|
+
});
|
|
181
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
182
|
+
} catch (err) {
|
|
183
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
184
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
server2.tool(
|
|
189
|
+
"resume-themes",
|
|
190
|
+
"List all available resume themes. Returns theme IDs, names, and descriptions.",
|
|
191
|
+
{},
|
|
192
|
+
async () => {
|
|
193
|
+
try {
|
|
194
|
+
const result = await client2.resume.themes();
|
|
195
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
196
|
+
} catch (err) {
|
|
197
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
198
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
server2.tool(
|
|
203
|
+
"resume-import-rx",
|
|
204
|
+
"Import a resume from Reactive Resume (RxResume) format into JSON Resume format.",
|
|
205
|
+
{
|
|
206
|
+
data: z3.record(z3.unknown()).describe("RxResume data object to import")
|
|
207
|
+
},
|
|
208
|
+
async (params) => {
|
|
209
|
+
try {
|
|
210
|
+
const result = await client2.resume.importRxResume({ data: params.data });
|
|
211
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
212
|
+
} catch (err) {
|
|
213
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
214
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
server2.tool(
|
|
219
|
+
"resume-export-rx",
|
|
220
|
+
"Export a JSON Resume to Reactive Resume (RxResume) format.",
|
|
221
|
+
{
|
|
222
|
+
resume: z3.record(z3.unknown()).describe("Resume object in JSON Resume format")
|
|
223
|
+
},
|
|
224
|
+
async (params) => {
|
|
225
|
+
try {
|
|
226
|
+
const result = await client2.resume.exportRxResume({ resume: params.resume });
|
|
227
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
228
|
+
} catch (err) {
|
|
229
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
230
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
);
|
|
234
|
+
server2.tool(
|
|
235
|
+
"master-resume-create",
|
|
236
|
+
"Create a new master resume. Returns the saved master resume with its ID.",
|
|
237
|
+
{
|
|
238
|
+
label: z3.string().describe("Label/name for this master resume"),
|
|
239
|
+
rawText: z3.string().describe("Raw resume text content"),
|
|
240
|
+
isDefault: z3.boolean().optional().describe("Set as default master resume")
|
|
241
|
+
},
|
|
242
|
+
async (params) => {
|
|
243
|
+
try {
|
|
244
|
+
const result = await client2.resume.createMaster({
|
|
245
|
+
label: params.label,
|
|
246
|
+
rawText: params.rawText,
|
|
247
|
+
isDefault: params.isDefault
|
|
248
|
+
});
|
|
249
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
250
|
+
} catch (err) {
|
|
251
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
252
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
server2.tool(
|
|
257
|
+
"master-resume-list",
|
|
258
|
+
"List all master resumes. Returns an array of master resume objects.",
|
|
259
|
+
{},
|
|
260
|
+
async () => {
|
|
261
|
+
try {
|
|
262
|
+
const result = await client2.resume.listMasters();
|
|
263
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
264
|
+
} catch (err) {
|
|
265
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
266
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
server2.tool(
|
|
271
|
+
"master-resume-get",
|
|
272
|
+
"Get a master resume by ID. Returns the full master resume object.",
|
|
273
|
+
{
|
|
274
|
+
id: z3.string().describe("Master resume ID")
|
|
275
|
+
},
|
|
276
|
+
async (params) => {
|
|
277
|
+
try {
|
|
278
|
+
const result = await client2.resume.getMaster(params.id);
|
|
279
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
280
|
+
} catch (err) {
|
|
281
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
282
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
server2.tool(
|
|
287
|
+
"master-resume-update",
|
|
288
|
+
"Update a master resume by ID. Returns the updated master resume.",
|
|
289
|
+
{
|
|
290
|
+
id: z3.string().describe("Master resume ID"),
|
|
291
|
+
label: z3.string().optional().describe("Updated label/name"),
|
|
292
|
+
rawText: z3.string().optional().describe("Updated raw resume text"),
|
|
293
|
+
isDefault: z3.boolean().optional().describe("Set as default master resume")
|
|
294
|
+
},
|
|
295
|
+
async (params) => {
|
|
296
|
+
try {
|
|
297
|
+
const result = await client2.resume.updateMaster(params.id, {
|
|
298
|
+
label: params.label,
|
|
299
|
+
rawText: params.rawText,
|
|
300
|
+
isDefault: params.isDefault
|
|
301
|
+
});
|
|
302
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
303
|
+
} catch (err) {
|
|
304
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
305
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
server2.tool(
|
|
310
|
+
"master-resume-delete",
|
|
311
|
+
"Delete a master resume by ID.",
|
|
312
|
+
{
|
|
313
|
+
id: z3.string().describe("Master resume ID")
|
|
314
|
+
},
|
|
315
|
+
async (params) => {
|
|
316
|
+
try {
|
|
317
|
+
await client2.resume.deleteMaster(params.id);
|
|
318
|
+
return { content: [{ type: "text", text: JSON.stringify({ deleted: true, id: params.id }) }] };
|
|
319
|
+
} catch (err) {
|
|
320
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
321
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/tools/upload.ts
|
|
328
|
+
import { z as z4 } from "zod";
|
|
329
|
+
function registerUploadTools(server2, client2) {
|
|
330
|
+
server2.tool(
|
|
331
|
+
"upload-resume",
|
|
332
|
+
"Upload and parse a resume file. Accepts base64-encoded file content. Returns parsed resume data.",
|
|
333
|
+
{
|
|
334
|
+
fileBase64: z4.string().describe("Base64-encoded file content (PDF, DOCX, etc.)"),
|
|
335
|
+
filename: z4.string().describe("Original filename with extension (e.g. resume.pdf)"),
|
|
336
|
+
contentType: z4.string().optional().describe("MIME type (e.g. application/pdf)")
|
|
337
|
+
},
|
|
338
|
+
async (params) => {
|
|
339
|
+
try {
|
|
340
|
+
const buffer = Buffer.from(params.fileBase64, "base64");
|
|
341
|
+
const result = await client2.upload.resume(buffer, {
|
|
342
|
+
filename: params.filename,
|
|
343
|
+
contentType: params.contentType
|
|
344
|
+
});
|
|
345
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
346
|
+
} catch (err) {
|
|
347
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
348
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
server2.tool(
|
|
353
|
+
"upload-job-file",
|
|
354
|
+
"Upload and parse a job description file. Accepts base64-encoded file content. Returns parsed job data.",
|
|
355
|
+
{
|
|
356
|
+
fileBase64: z4.string().describe("Base64-encoded file content (PDF, DOCX, etc.)"),
|
|
357
|
+
filename: z4.string().describe("Original filename with extension"),
|
|
358
|
+
contentType: z4.string().optional().describe("MIME type")
|
|
359
|
+
},
|
|
360
|
+
async (params) => {
|
|
361
|
+
try {
|
|
362
|
+
const buffer = Buffer.from(params.fileBase64, "base64");
|
|
363
|
+
const result = await client2.upload.jobFile(buffer, {
|
|
364
|
+
filename: params.filename,
|
|
365
|
+
contentType: params.contentType
|
|
366
|
+
});
|
|
367
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
368
|
+
} catch (err) {
|
|
369
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
370
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
);
|
|
374
|
+
server2.tool(
|
|
375
|
+
"upload-job-text",
|
|
376
|
+
"Upload a job description as plain text. Returns parsed job data.",
|
|
377
|
+
{
|
|
378
|
+
text: z4.string().describe("Job description text"),
|
|
379
|
+
source: z4.string().optional().describe("Source URL or identifier for the job posting")
|
|
380
|
+
},
|
|
381
|
+
async (params) => {
|
|
382
|
+
try {
|
|
383
|
+
const result = await client2.upload.jobText({
|
|
384
|
+
text: params.text,
|
|
385
|
+
source: params.source
|
|
386
|
+
});
|
|
387
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
388
|
+
} catch (err) {
|
|
389
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
390
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/tools/sessions.ts
|
|
397
|
+
import { z as z5 } from "zod";
|
|
398
|
+
function registerSessionTools(server2, client2) {
|
|
399
|
+
server2.tool(
|
|
400
|
+
"session-create",
|
|
401
|
+
"Create a new session. Returns the created session object with its ID.",
|
|
402
|
+
{
|
|
403
|
+
metadata: z5.record(z5.unknown()).optional().describe("Optional session metadata (e.g. agentType, source)")
|
|
404
|
+
},
|
|
405
|
+
async (params) => {
|
|
406
|
+
try {
|
|
407
|
+
const result = await client2.sessions.create({
|
|
408
|
+
metadata: params.metadata
|
|
409
|
+
});
|
|
410
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
411
|
+
} catch (err) {
|
|
412
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
413
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
server2.tool(
|
|
418
|
+
"session-list",
|
|
419
|
+
"List sessions with optional filtering and pagination. Returns an array of session objects.",
|
|
420
|
+
{
|
|
421
|
+
page: z5.number().optional().describe("Page number for pagination"),
|
|
422
|
+
limit: z5.number().optional().describe("Number of sessions per page"),
|
|
423
|
+
agentType: z5.string().optional().describe("Filter by agent type")
|
|
424
|
+
},
|
|
425
|
+
async (params) => {
|
|
426
|
+
try {
|
|
427
|
+
const result = await client2.sessions.list({
|
|
428
|
+
page: params.page,
|
|
429
|
+
limit: params.limit,
|
|
430
|
+
agentType: params.agentType
|
|
431
|
+
});
|
|
432
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
433
|
+
} catch (err) {
|
|
434
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
435
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
);
|
|
439
|
+
server2.tool(
|
|
440
|
+
"session-get",
|
|
441
|
+
"Get a session by ID. Returns the session object with generation history.",
|
|
442
|
+
{
|
|
443
|
+
id: z5.string().describe("Session ID")
|
|
444
|
+
},
|
|
445
|
+
async (params) => {
|
|
446
|
+
try {
|
|
447
|
+
const result = await client2.sessions.get(params.id);
|
|
448
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
449
|
+
} catch (err) {
|
|
450
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
451
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
server2.tool(
|
|
456
|
+
"session-hydrate",
|
|
457
|
+
"Hydrate a session \u2014 returns the full session with all artifacts and logs.",
|
|
458
|
+
{
|
|
459
|
+
id: z5.string().describe("Session ID")
|
|
460
|
+
},
|
|
461
|
+
async (params) => {
|
|
462
|
+
try {
|
|
463
|
+
const result = await client2.sessions.hydrate(params.id);
|
|
464
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
465
|
+
} catch (err) {
|
|
466
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
467
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
server2.tool(
|
|
472
|
+
"session-delete",
|
|
473
|
+
"Delete a session by ID.",
|
|
474
|
+
{
|
|
475
|
+
id: z5.string().describe("Session ID")
|
|
476
|
+
},
|
|
477
|
+
async (params) => {
|
|
478
|
+
try {
|
|
479
|
+
await client2.sessions.delete(params.id);
|
|
480
|
+
return { content: [{ type: "text", text: JSON.stringify({ deleted: true, id: params.id }) }] };
|
|
481
|
+
} catch (err) {
|
|
482
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
483
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/tools/settings.ts
|
|
490
|
+
import { z as z6 } from "zod";
|
|
491
|
+
function registerSettingsTools(server2, client2) {
|
|
492
|
+
server2.tool(
|
|
493
|
+
"settings-profile",
|
|
494
|
+
"Get the current user's profile. Returns email, name, plan, and credit balance.",
|
|
495
|
+
{},
|
|
496
|
+
async () => {
|
|
497
|
+
try {
|
|
498
|
+
const result = await client2.settings.getProfile();
|
|
499
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
500
|
+
} catch (err) {
|
|
501
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
502
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
server2.tool(
|
|
507
|
+
"settings-preferences-get",
|
|
508
|
+
"Get the current user's preferences.",
|
|
509
|
+
{},
|
|
510
|
+
async () => {
|
|
511
|
+
try {
|
|
512
|
+
const result = await client2.settings.getPreferences();
|
|
513
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
514
|
+
} catch (err) {
|
|
515
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
516
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
);
|
|
520
|
+
server2.tool(
|
|
521
|
+
"settings-preferences-update",
|
|
522
|
+
"Update the current user's preferences. Returns the updated preferences.",
|
|
523
|
+
{
|
|
524
|
+
preferences: z6.record(z6.unknown()).describe("Preferences object to update")
|
|
525
|
+
},
|
|
526
|
+
async (params) => {
|
|
527
|
+
try {
|
|
528
|
+
const result = await client2.settings.updatePreferences({
|
|
529
|
+
preferences: params.preferences
|
|
530
|
+
});
|
|
531
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
532
|
+
} catch (err) {
|
|
533
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
534
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
server2.tool(
|
|
539
|
+
"settings-usage-summary",
|
|
540
|
+
"Get a summary of the user's API usage and credit consumption.",
|
|
541
|
+
{},
|
|
542
|
+
async () => {
|
|
543
|
+
try {
|
|
544
|
+
const result = await client2.settings.getUsageSummary();
|
|
545
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
546
|
+
} catch (err) {
|
|
547
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
548
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
);
|
|
552
|
+
server2.tool(
|
|
553
|
+
"settings-usage-logs",
|
|
554
|
+
"Get paginated usage logs. Returns individual usage entries with action, credits, and timestamps.",
|
|
555
|
+
{
|
|
556
|
+
offset: z6.number().optional().describe("Offset for pagination"),
|
|
557
|
+
limit: z6.number().optional().describe("Number of entries to return")
|
|
558
|
+
},
|
|
559
|
+
async (params) => {
|
|
560
|
+
try {
|
|
561
|
+
const result = await client2.settings.getUsageLogs({
|
|
562
|
+
offset: params.offset,
|
|
563
|
+
limit: params.limit
|
|
564
|
+
});
|
|
565
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
566
|
+
} catch (err) {
|
|
567
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
568
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
);
|
|
572
|
+
server2.tool(
|
|
573
|
+
"api-key-create",
|
|
574
|
+
"Create a new platform API key. The key value is shown ONLY in this response \u2014 save it immediately.",
|
|
575
|
+
{
|
|
576
|
+
label: z6.string().describe("Human-readable label for the API key"),
|
|
577
|
+
scopes: z6.array(z6.enum([
|
|
578
|
+
"jobs:write",
|
|
579
|
+
"jobs:read",
|
|
580
|
+
"sales:write",
|
|
581
|
+
"sales:read",
|
|
582
|
+
"sessions:read",
|
|
583
|
+
"sessions:write",
|
|
584
|
+
"settings:read",
|
|
585
|
+
"settings:write",
|
|
586
|
+
"upload:write",
|
|
587
|
+
"resume:read",
|
|
588
|
+
"resume:write",
|
|
589
|
+
"ats:write",
|
|
590
|
+
"webhook:read",
|
|
591
|
+
"webhook:write"
|
|
592
|
+
])).describe("Permission scopes for the key")
|
|
593
|
+
},
|
|
594
|
+
async (params) => {
|
|
595
|
+
try {
|
|
596
|
+
const result = await client2.settings.createApiKey({
|
|
597
|
+
label: params.label,
|
|
598
|
+
scopes: params.scopes
|
|
599
|
+
});
|
|
600
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
601
|
+
} catch (err) {
|
|
602
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
603
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
server2.tool(
|
|
608
|
+
"api-key-list",
|
|
609
|
+
"List all platform API keys. Returns key metadata (hash, name, scopes) \u2014 NOT the key values.",
|
|
610
|
+
{},
|
|
611
|
+
async () => {
|
|
612
|
+
try {
|
|
613
|
+
const result = await client2.settings.listApiKeys();
|
|
614
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
615
|
+
} catch (err) {
|
|
616
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
617
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
);
|
|
621
|
+
server2.tool(
|
|
622
|
+
"api-key-revoke",
|
|
623
|
+
"Revoke (delete) a platform API key by its hash.",
|
|
624
|
+
{
|
|
625
|
+
hash: z6.string().describe("API key hash to revoke")
|
|
626
|
+
},
|
|
627
|
+
async (params) => {
|
|
628
|
+
try {
|
|
629
|
+
await client2.settings.revokeApiKey(params.hash);
|
|
630
|
+
return { content: [{ type: "text", text: JSON.stringify({ revoked: true, hash: params.hash }) }] };
|
|
631
|
+
} catch (err) {
|
|
632
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
633
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
server2.tool(
|
|
638
|
+
"api-key-rotate",
|
|
639
|
+
"Rotate a platform API key \u2014 revokes the old key and returns a new one. Save the new key immediately.",
|
|
640
|
+
{
|
|
641
|
+
hash: z6.string().describe("API key hash to rotate")
|
|
642
|
+
},
|
|
643
|
+
async (params) => {
|
|
644
|
+
try {
|
|
645
|
+
const result = await client2.settings.rotateApiKey(params.hash);
|
|
646
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
647
|
+
} catch (err) {
|
|
648
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
649
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/tools/content.ts
|
|
656
|
+
import { z as z7 } from "zod";
|
|
657
|
+
function registerContentTools(server2, client2) {
|
|
658
|
+
server2.tool(
|
|
659
|
+
"content-save",
|
|
660
|
+
"Save a source document for use as context in AI generation. Returns success status.",
|
|
661
|
+
{
|
|
662
|
+
docType: z7.enum([
|
|
663
|
+
"original_cv",
|
|
664
|
+
"extensive_cv",
|
|
665
|
+
"cover_letter",
|
|
666
|
+
"cv_strategy",
|
|
667
|
+
"cover_letter_strategy",
|
|
668
|
+
"cold_email_strategy",
|
|
669
|
+
"recon_strategy",
|
|
670
|
+
"company_context"
|
|
671
|
+
]).describe("Type of source document"),
|
|
672
|
+
content: z7.string().describe("Document content text")
|
|
673
|
+
},
|
|
674
|
+
async (params) => {
|
|
675
|
+
try {
|
|
676
|
+
const result = await client2.content.save({
|
|
677
|
+
docType: params.docType,
|
|
678
|
+
content: params.content
|
|
679
|
+
});
|
|
680
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
681
|
+
} catch (err) {
|
|
682
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
683
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
);
|
|
687
|
+
server2.tool(
|
|
688
|
+
"content-delete-generation",
|
|
689
|
+
"Delete a generation and all its artifacts from a session.",
|
|
690
|
+
{
|
|
691
|
+
id: z7.string().describe("Generation ID to delete"),
|
|
692
|
+
sessionId: z7.string().describe("Session ID that owns the generation")
|
|
693
|
+
},
|
|
694
|
+
async (params) => {
|
|
695
|
+
try {
|
|
696
|
+
const httpClient = client2.content.httpClient;
|
|
697
|
+
const result = await httpClient.request(
|
|
698
|
+
`/content/generations/${encodeURIComponent(params.id)}`,
|
|
699
|
+
{ method: "DELETE", query: { sessionId: params.sessionId } }
|
|
700
|
+
);
|
|
701
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
702
|
+
} catch (err) {
|
|
703
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
704
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/tools/shares.ts
|
|
711
|
+
import { z as z8 } from "zod";
|
|
712
|
+
function registerSharesTools(server2, client2) {
|
|
713
|
+
server2.tool(
|
|
714
|
+
"share-create",
|
|
715
|
+
"Create a shareable public link for a generation's artifacts. Returns a slug and public URL.",
|
|
716
|
+
{
|
|
717
|
+
sessionId: z8.string().describe("Session ID containing the generation"),
|
|
718
|
+
generationId: z8.string().describe("Generation ID to share")
|
|
719
|
+
},
|
|
720
|
+
async (params) => {
|
|
721
|
+
try {
|
|
722
|
+
const result = await client2.shares.create({
|
|
723
|
+
sessionId: params.sessionId,
|
|
724
|
+
generationId: params.generationId
|
|
725
|
+
});
|
|
726
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
727
|
+
} catch (err) {
|
|
728
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
729
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
);
|
|
733
|
+
server2.tool(
|
|
734
|
+
"share-stats",
|
|
735
|
+
"Get statistics about your shared links (view counts, etc.).",
|
|
736
|
+
{},
|
|
737
|
+
async () => {
|
|
738
|
+
try {
|
|
739
|
+
const result = await client2.shares.getStats();
|
|
740
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
741
|
+
} catch (err) {
|
|
742
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
743
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
);
|
|
747
|
+
server2.tool(
|
|
748
|
+
"share-get-public",
|
|
749
|
+
"Get a publicly shared resource by its slug.",
|
|
750
|
+
{
|
|
751
|
+
slug: z8.string().describe("Public share slug")
|
|
752
|
+
},
|
|
753
|
+
async (params) => {
|
|
754
|
+
try {
|
|
755
|
+
const result = await client2.shares.getPublic(params.slug);
|
|
756
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
757
|
+
} catch (err) {
|
|
758
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
759
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// src/tools/documents.ts
|
|
766
|
+
import { z as z9 } from "zod";
|
|
767
|
+
function registerDocumentTools(server2, client2) {
|
|
768
|
+
server2.tool(
|
|
769
|
+
"document-download",
|
|
770
|
+
"Download a document by its storage path. Returns the file content or a download URL.",
|
|
771
|
+
{
|
|
772
|
+
path: z9.string().describe("Document storage path")
|
|
773
|
+
},
|
|
774
|
+
async (params) => {
|
|
775
|
+
try {
|
|
776
|
+
const response = await client2.documents.download(params.path);
|
|
777
|
+
const text = await response.text();
|
|
778
|
+
return { content: [{ type: "text", text }] };
|
|
779
|
+
} catch (err) {
|
|
780
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
781
|
+
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// src/index.ts
|
|
788
|
+
var apiKey = process.env.LLMC_API_KEY;
|
|
789
|
+
if (!apiKey) {
|
|
790
|
+
console.error("LLMC_API_KEY environment variable is required");
|
|
791
|
+
process.exit(1);
|
|
792
|
+
}
|
|
793
|
+
var client = new LLMConveyors({ apiKey });
|
|
794
|
+
var server = new McpServer({
|
|
795
|
+
name: "llmconveyors",
|
|
796
|
+
version: "0.1.0"
|
|
797
|
+
});
|
|
798
|
+
registerAgentTools(server, client);
|
|
799
|
+
registerAtsTools(server, client);
|
|
800
|
+
registerResumeTools(server, client);
|
|
801
|
+
registerUploadTools(server, client);
|
|
802
|
+
registerSessionTools(server, client);
|
|
803
|
+
registerSettingsTools(server, client);
|
|
804
|
+
registerContentTools(server, client);
|
|
805
|
+
registerSharesTools(server, client);
|
|
806
|
+
registerDocumentTools(server, client);
|
|
807
|
+
var transport = new StdioServerTransport();
|
|
808
|
+
await server.connect(transport);
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "llmconveyors-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server that connects AI agents to LLM Conveyors — run Job Hunter, B2B Sales, and other AI agents from Claude, Cursor, or any MCP client",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"llmconveyors-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
18
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mcp",
|
|
25
|
+
"mcp-server",
|
|
26
|
+
"model-context-protocol",
|
|
27
|
+
"llm-conveyors",
|
|
28
|
+
"ai-agents",
|
|
29
|
+
"claude",
|
|
30
|
+
"cursor",
|
|
31
|
+
"job-hunting",
|
|
32
|
+
"resume",
|
|
33
|
+
"ats",
|
|
34
|
+
"b2b-sales",
|
|
35
|
+
"cold-email",
|
|
36
|
+
"ai-tools"
|
|
37
|
+
],
|
|
38
|
+
"author": "LLM Conveyors <hello@llmconveyors.com> (https://llmconveyors.com)",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"homepage": "https://github.com/llmconveyors/llmconveyors-mcp#readme",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/llmconveyors/llmconveyors-mcp.git"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/llmconveyors/llmconveyors-mcp/issues"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
53
|
+
"llmconveyors": "^0.1.0",
|
|
54
|
+
"zod": "^3.24.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^20.11.0",
|
|
58
|
+
"tsup": "^8.0.0",
|
|
59
|
+
"typescript": "^5.5.0"
|
|
60
|
+
}
|
|
61
|
+
}
|