riveter-mcp-server 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 +65 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +188 -0
- package/dist/index.js.map +1 -0
- package/dist/openapi-parser.d.ts +26 -0
- package/dist/openapi-parser.js +103 -0
- package/dist/openapi-parser.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cody
|
|
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,65 @@
|
|
|
1
|
+
# Riveter MCP Server
|
|
2
|
+
|
|
3
|
+
sup.
|
|
4
|
+
|
|
5
|
+
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that connects Claude to the [Riveter API](https://riveterhq.com). Run enrichments, scrape webpages, manage monitors, and more — directly from Claude.
|
|
6
|
+
|
|
7
|
+
Tools are generated dynamically from Riveter's [OpenAPI spec](https://docs.riveterhq.com/openapi.yaml), so they stay up to date automatically.
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
### 1. Get a Riveter API key
|
|
12
|
+
|
|
13
|
+
Go to [app.riveterhq.com/settings/api](https://app.riveterhq.com/settings/api) and create an API key.
|
|
14
|
+
|
|
15
|
+
### 2. Configure Claude Desktop
|
|
16
|
+
|
|
17
|
+
Open your Claude Desktop config file:
|
|
18
|
+
|
|
19
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
20
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
21
|
+
|
|
22
|
+
Add the Riveter server:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"riveter": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "riveter-mcp-server"],
|
|
30
|
+
"env": {
|
|
31
|
+
"RIVETER_API_KEY": "sk_riv_your_key_here"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Environment variables
|
|
39
|
+
|
|
40
|
+
| Variable | Required | Default | Description |
|
|
41
|
+
| ---------------------- | -------- | ----------------------------------------- | -------------------- |
|
|
42
|
+
| `RIVETER_API_KEY` | Yes | — | Your Riveter API key |
|
|
43
|
+
| `RIVETER_API_BASE_URL` | No | `https://api.riveterhq.com/v1` | API base URL |
|
|
44
|
+
| `RIVETER_OPENAPI_URL` | No | `https://docs.riveterhq.com/openapi.yaml` | OpenAPI spec URL |
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
On startup, the server:
|
|
49
|
+
|
|
50
|
+
1. Fetches the OpenAPI spec from `docs.riveterhq.com/openapi.yaml`
|
|
51
|
+
2. Parses each endpoint into an MCP tool with typed parameters
|
|
52
|
+
3. Serves the tools over stdio for Claude to use
|
|
53
|
+
|
|
54
|
+
When you update the API docs, the MCP server picks up the changes next time Claude launches — no rebuild or republish needed.
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install
|
|
60
|
+
npm run dev
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { parseOpenApiSpec } from "./openapi-parser.js";
|
|
6
|
+
const OPENAPI_SPEC_URL = process.env.RIVETER_OPENAPI_URL ||
|
|
7
|
+
"https://docs.riveterhq.com/openapi.yaml";
|
|
8
|
+
const API_BASE_URL = process.env.RIVETER_API_BASE_URL || "https://api.riveterhq.com/v1";
|
|
9
|
+
const API_KEY = process.env.RIVETER_API_KEY || "";
|
|
10
|
+
async function fetchSpec() {
|
|
11
|
+
const res = await fetch(OPENAPI_SPEC_URL);
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
throw new Error(`Failed to fetch OpenAPI spec from ${OPENAPI_SPEC_URL}: ${res.status}`);
|
|
14
|
+
}
|
|
15
|
+
return res.text();
|
|
16
|
+
}
|
|
17
|
+
async function callApi(method, path, queryParams, body) {
|
|
18
|
+
const url = new URL(`${API_BASE_URL}${path}`);
|
|
19
|
+
if (queryParams) {
|
|
20
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
21
|
+
if (value !== undefined && value !== "") {
|
|
22
|
+
url.searchParams.set(key, value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const headers = {
|
|
27
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
Accept: "application/json",
|
|
30
|
+
};
|
|
31
|
+
const fetchOptions = { method: method.toUpperCase(), headers };
|
|
32
|
+
if (body && (method === "post" || method === "put" || method === "patch")) {
|
|
33
|
+
fetchOptions.body = JSON.stringify(body);
|
|
34
|
+
}
|
|
35
|
+
const res = await fetch(url.toString(), fetchOptions);
|
|
36
|
+
const text = await res.text();
|
|
37
|
+
let data;
|
|
38
|
+
try {
|
|
39
|
+
data = JSON.parse(text);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
data = { raw_response: text, status_code: res.status };
|
|
43
|
+
}
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
return {
|
|
46
|
+
error: true,
|
|
47
|
+
status_code: res.status,
|
|
48
|
+
...(typeof data === "object" && data !== null ? data : { message: text }),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return data;
|
|
52
|
+
}
|
|
53
|
+
// Workflow hints appended to tool descriptions so Claude knows the async patterns
|
|
54
|
+
const WORKFLOW_HINTS = {
|
|
55
|
+
runNewEnrichment: "\n\n**Workflow:** This starts an async run. Use the returned `run_key` with `get_run_status` to poll until status is 'success', then `get_run_data` to retrieve results.",
|
|
56
|
+
runExistingEnrichment: "\n\n**Workflow:** This starts an async run. Use the returned `run_key` with `get_run_status` to poll until status is 'success', then `get_run_data` to retrieve results.",
|
|
57
|
+
getRunStatus: "\n\n**Workflow:** Poll this endpoint until `status` is 'success' or 'stopped'. Typical runs take 10-120 seconds. Poll every 5-10 seconds.",
|
|
58
|
+
getRunData: "\n\n**Workflow:** Call this after `get_run_status` shows 'success' to get the full results.",
|
|
59
|
+
monitorEnrichment: "\n\n**Workflow:** Creates a scheduled monitor. Use the returned `monitor_uuid` with `get_monitor_status` to check on it, or `pause_monitor` to pause it.",
|
|
60
|
+
};
|
|
61
|
+
function operationIdToToolName(operationId) {
|
|
62
|
+
return operationId
|
|
63
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
64
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
65
|
+
.toLowerCase();
|
|
66
|
+
}
|
|
67
|
+
function buildZodShape(params, bodyProps) {
|
|
68
|
+
const shape = {};
|
|
69
|
+
for (const param of params) {
|
|
70
|
+
let fieldSchema;
|
|
71
|
+
switch (param.schema.type) {
|
|
72
|
+
case "integer":
|
|
73
|
+
fieldSchema = z.number().int().describe(param.description || param.name);
|
|
74
|
+
break;
|
|
75
|
+
case "boolean":
|
|
76
|
+
fieldSchema = z.boolean().describe(param.description || param.name);
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
fieldSchema = z.string().describe(param.description || param.name);
|
|
80
|
+
}
|
|
81
|
+
if (!param.required) {
|
|
82
|
+
fieldSchema = fieldSchema.optional();
|
|
83
|
+
}
|
|
84
|
+
shape[param.name] = fieldSchema;
|
|
85
|
+
}
|
|
86
|
+
for (const [name, prop] of Object.entries(bodyProps)) {
|
|
87
|
+
if (shape[name])
|
|
88
|
+
continue;
|
|
89
|
+
let fieldSchema;
|
|
90
|
+
switch (prop.type) {
|
|
91
|
+
case "integer":
|
|
92
|
+
fieldSchema = z.number().int().describe(prop.description || name);
|
|
93
|
+
break;
|
|
94
|
+
case "number":
|
|
95
|
+
fieldSchema = z.number().describe(prop.description || name);
|
|
96
|
+
break;
|
|
97
|
+
case "boolean":
|
|
98
|
+
fieldSchema = z.boolean().describe(prop.description || name);
|
|
99
|
+
break;
|
|
100
|
+
case "array":
|
|
101
|
+
fieldSchema = z.array(z.any()).describe(prop.description || name);
|
|
102
|
+
break;
|
|
103
|
+
case "object":
|
|
104
|
+
fieldSchema = z
|
|
105
|
+
.record(z.string(), z.any())
|
|
106
|
+
.describe(prop.description || name);
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
fieldSchema = z.string().describe(prop.description || name);
|
|
110
|
+
}
|
|
111
|
+
if (!prop.required) {
|
|
112
|
+
fieldSchema = fieldSchema.optional();
|
|
113
|
+
}
|
|
114
|
+
shape[name] = fieldSchema;
|
|
115
|
+
}
|
|
116
|
+
return shape;
|
|
117
|
+
}
|
|
118
|
+
async function main() {
|
|
119
|
+
if (!API_KEY) {
|
|
120
|
+
console.error("RIVETER_API_KEY environment variable is required. Get one at https://app.riveterhq.com/settings/api");
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
const server = new McpServer({
|
|
124
|
+
name: "riveter",
|
|
125
|
+
version: "0.1.0",
|
|
126
|
+
});
|
|
127
|
+
let specText;
|
|
128
|
+
try {
|
|
129
|
+
specText = await fetchSpec();
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
console.error(`Failed to fetch OpenAPI spec: ${err}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
const operations = parseOpenApiSpec(specText);
|
|
136
|
+
for (const op of operations) {
|
|
137
|
+
const toolName = operationIdToToolName(op.operationId);
|
|
138
|
+
const hint = WORKFLOW_HINTS[op.operationId] || "";
|
|
139
|
+
const description = (op.summary ? `${op.summary}\n\n` : "") + op.description + hint;
|
|
140
|
+
const shape = buildZodShape(op.parameters, op.requestBodyProperties);
|
|
141
|
+
const queryParamNames = new Set(op.parameters.map((p) => p.name));
|
|
142
|
+
const method = op.method;
|
|
143
|
+
const path = op.path;
|
|
144
|
+
server.tool(toolName, description, shape, async (args) => {
|
|
145
|
+
const queryParams = {};
|
|
146
|
+
const bodyParams = {};
|
|
147
|
+
for (const [key, value] of Object.entries(args)) {
|
|
148
|
+
if (value === undefined)
|
|
149
|
+
continue;
|
|
150
|
+
if (queryParamNames.has(key)) {
|
|
151
|
+
queryParams[key] = String(value);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
bodyParams[key] = value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const result = await callApi(method, path, Object.keys(queryParams).length > 0 ? queryParams : undefined, Object.keys(bodyParams).length > 0 ? bodyParams : undefined);
|
|
159
|
+
return {
|
|
160
|
+
content: [
|
|
161
|
+
{
|
|
162
|
+
type: "text",
|
|
163
|
+
text: JSON.stringify(result, null, 2),
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
return {
|
|
170
|
+
content: [
|
|
171
|
+
{
|
|
172
|
+
type: "text",
|
|
173
|
+
text: `API request failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
isError: true,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
const transport = new StdioServerTransport();
|
|
182
|
+
await server.connect(transport);
|
|
183
|
+
}
|
|
184
|
+
main().catch((err) => {
|
|
185
|
+
console.error("Fatal error:", err);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
});
|
|
188
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface OpenApiParameter {
|
|
2
|
+
name: string;
|
|
3
|
+
in: "query" | "path" | "header";
|
|
4
|
+
required: boolean;
|
|
5
|
+
description: string;
|
|
6
|
+
schema: {
|
|
7
|
+
type: string;
|
|
8
|
+
enum?: string[];
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface OpenApiBodyProperty {
|
|
12
|
+
type: string;
|
|
13
|
+
description: string;
|
|
14
|
+
required: boolean;
|
|
15
|
+
enum?: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface OpenApiOperation {
|
|
18
|
+
operationId: string;
|
|
19
|
+
method: string;
|
|
20
|
+
path: string;
|
|
21
|
+
summary: string;
|
|
22
|
+
description: string;
|
|
23
|
+
parameters: OpenApiParameter[];
|
|
24
|
+
requestBodyProperties: Record<string, OpenApiBodyProperty>;
|
|
25
|
+
}
|
|
26
|
+
export declare function parseOpenApiSpec(specText: string): OpenApiOperation[];
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { parse as parseYaml } from "yaml";
|
|
2
|
+
function cleanDescription(desc) {
|
|
3
|
+
if (!desc)
|
|
4
|
+
return "";
|
|
5
|
+
// Strip markdown code blocks and excessive whitespace for cleaner tool descriptions
|
|
6
|
+
return desc
|
|
7
|
+
.replace(/```[\s\S]*?```/g, "")
|
|
8
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
9
|
+
.trim();
|
|
10
|
+
}
|
|
11
|
+
function resolveRef(spec, ref) {
|
|
12
|
+
// Resolve $ref like "#/components/schemas/Foo"
|
|
13
|
+
const parts = ref.replace(/^#\//, "").split("/");
|
|
14
|
+
let current = spec;
|
|
15
|
+
for (const part of parts) {
|
|
16
|
+
if (typeof current !== "object" || current === null)
|
|
17
|
+
return undefined;
|
|
18
|
+
current = current[part];
|
|
19
|
+
}
|
|
20
|
+
return current;
|
|
21
|
+
}
|
|
22
|
+
function extractRequiredFields(schema) {
|
|
23
|
+
if (Array.isArray(schema.required)) {
|
|
24
|
+
return schema.required;
|
|
25
|
+
}
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
export function parseOpenApiSpec(specText) {
|
|
29
|
+
const spec = parseYaml(specText);
|
|
30
|
+
const paths = spec.paths;
|
|
31
|
+
if (!paths)
|
|
32
|
+
return [];
|
|
33
|
+
const operations = [];
|
|
34
|
+
const httpMethods = ["get", "post", "put", "patch", "delete"];
|
|
35
|
+
for (const [path, pathItem] of Object.entries(paths)) {
|
|
36
|
+
for (const method of httpMethods) {
|
|
37
|
+
const operation = pathItem[method];
|
|
38
|
+
if (!operation)
|
|
39
|
+
continue;
|
|
40
|
+
const operationId = operation.operationId;
|
|
41
|
+
if (!operationId)
|
|
42
|
+
continue;
|
|
43
|
+
// Parse parameters
|
|
44
|
+
const rawParams = operation.parameters || [];
|
|
45
|
+
const parameters = rawParams.map((p) => {
|
|
46
|
+
let paramSchema = p.schema;
|
|
47
|
+
if (paramSchema && "$ref" in paramSchema) {
|
|
48
|
+
paramSchema = resolveRef(spec, paramSchema.$ref) || paramSchema;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
name: p.name,
|
|
52
|
+
in: p.in,
|
|
53
|
+
required: p.required || false,
|
|
54
|
+
description: cleanDescription(p.description),
|
|
55
|
+
schema: {
|
|
56
|
+
type: paramSchema?.type || "string",
|
|
57
|
+
enum: paramSchema?.enum,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
// Parse request body properties
|
|
62
|
+
const requestBodyProperties = {};
|
|
63
|
+
const requestBody = operation.requestBody;
|
|
64
|
+
if (requestBody) {
|
|
65
|
+
const content = requestBody.content;
|
|
66
|
+
const jsonContent = content?.["application/json"];
|
|
67
|
+
if (jsonContent) {
|
|
68
|
+
let schema = jsonContent.schema;
|
|
69
|
+
if (schema && "$ref" in schema) {
|
|
70
|
+
schema = resolveRef(spec, schema.$ref) || schema;
|
|
71
|
+
}
|
|
72
|
+
if (schema) {
|
|
73
|
+
const requiredFields = extractRequiredFields(schema);
|
|
74
|
+
const properties = schema.properties || {};
|
|
75
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
76
|
+
let resolved = propSchema;
|
|
77
|
+
if ("$ref" in resolved) {
|
|
78
|
+
resolved = resolveRef(spec, resolved.$ref) || resolved;
|
|
79
|
+
}
|
|
80
|
+
requestBodyProperties[propName] = {
|
|
81
|
+
type: resolved.type || "object",
|
|
82
|
+
description: cleanDescription(resolved.description),
|
|
83
|
+
required: requiredFields.includes(propName),
|
|
84
|
+
enum: resolved.enum,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
operations.push({
|
|
91
|
+
operationId,
|
|
92
|
+
method,
|
|
93
|
+
path,
|
|
94
|
+
summary: operation.summary || "",
|
|
95
|
+
description: cleanDescription(operation.description),
|
|
96
|
+
parameters,
|
|
97
|
+
requestBodyProperties,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return operations;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=openapi-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi-parser.js","sourceRoot":"","sources":["../src/openapi-parser.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "riveter-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for the Riveter API — connects Claude to Riveter's enrichment, scraping, and monitoring tools",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"riveter-mcp-server": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "tsx watch src/index.ts",
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"typecheck": "tsc --noEmit"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
18
|
+
"yaml": "^2.7.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^20.11.25",
|
|
22
|
+
"tsx": "^4.7.1",
|
|
23
|
+
"typescript": "^5.4.2"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20.0.0"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"keywords": [
|
|
32
|
+
"mcp",
|
|
33
|
+
"riveter",
|
|
34
|
+
"claude",
|
|
35
|
+
"ai",
|
|
36
|
+
"enrichment",
|
|
37
|
+
"api"
|
|
38
|
+
],
|
|
39
|
+
"license": "MIT"
|
|
40
|
+
}
|