@vipcasso/mcp 0.0.0-stage → 0.0.1
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 +12 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/operations.d.ts +61 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +82 -0
- package/dist/operations.js.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +65 -0
- package/dist/server.js.map +1 -0
- package/dist/stdio.d.ts +3 -0
- package/dist/stdio.d.ts.map +1 -0
- package/dist/stdio.js +8 -0
- package/dist/stdio.js.map +1 -0
- package/package.json +44 -3
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
License — TBD at project kickoff.
|
|
2
|
+
|
|
3
|
+
Choose one and replace the contents of this file. Common options:
|
|
4
|
+
|
|
5
|
+
- **MIT** — permissive, broad reuse allowed. Most popular for open-source SaaS.
|
|
6
|
+
- **Apache-2.0** — permissive + explicit patent grant + trademark restriction.
|
|
7
|
+
- **BSL (Business Source License)** — source-available, time-limited commercial-use restriction. Common for commercial OSS-adjacent projects.
|
|
8
|
+
- **Proprietary / All Rights Reserved** — closed source. State explicitly to avoid ambiguity.
|
|
9
|
+
|
|
10
|
+
Reference: https://choosealicense.com/
|
|
11
|
+
|
|
12
|
+
Once chosen, log the decision in docs/DECISIONS.md with rationale (commercial posture, contributor expectations, dependency-license compatibility).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC3J,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,qBAAqB,EAA6D,MAAM,iBAAiB,CAAC;AAC3J,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP is a transport over the ONE router (blueprint §3.3): tools are derived
|
|
3
|
+
* from the live OpenAPI document, never hand-declared, so a new endpoint is a
|
|
4
|
+
* new tool (and a new CLI command) with no code here. Shared by the stdio
|
|
5
|
+
* server, the API's `POST /mcp` (W7) and the generated CLI.
|
|
6
|
+
*/
|
|
7
|
+
export interface ApiOperation {
|
|
8
|
+
toolName: string;
|
|
9
|
+
method: string;
|
|
10
|
+
path: string;
|
|
11
|
+
description: string;
|
|
12
|
+
pathParams: string[];
|
|
13
|
+
/** Declared query parameters (names), for a generated CLI's `--query k=v`. */
|
|
14
|
+
queryParams: string[];
|
|
15
|
+
/** The operation takes a request body. */
|
|
16
|
+
hasBody: boolean;
|
|
17
|
+
/** How the body travels: JSON, multipart (files), or none. */
|
|
18
|
+
bodyMediaType: "json" | "multipart" | null;
|
|
19
|
+
/** The JSON body's schema with `$ref`s inlined, so a tool list is self-contained (Codex on #418). */
|
|
20
|
+
bodySchema?: Record<string, unknown> | undefined;
|
|
21
|
+
/** The document says the body is required. */
|
|
22
|
+
bodyRequired: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface OpenApiOperation {
|
|
25
|
+
operationId?: string;
|
|
26
|
+
summary?: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
parameters?: {
|
|
29
|
+
name: string;
|
|
30
|
+
in: string;
|
|
31
|
+
}[];
|
|
32
|
+
requestBody?: {
|
|
33
|
+
required?: boolean;
|
|
34
|
+
content?: Record<string, {
|
|
35
|
+
schema?: unknown;
|
|
36
|
+
}>;
|
|
37
|
+
} | undefined;
|
|
38
|
+
}
|
|
39
|
+
export interface OpenApiDoc {
|
|
40
|
+
paths: Record<string, Record<string, OpenApiOperation>>;
|
|
41
|
+
components?: {
|
|
42
|
+
schemas?: Record<string, unknown>;
|
|
43
|
+
} | undefined;
|
|
44
|
+
}
|
|
45
|
+
/** Inline every `$ref` (against `components.schemas`) so a client needs nothing else; cycles become `{}`. */
|
|
46
|
+
export declare function resolveRefs(schema: unknown, doc: OpenApiDoc, seen?: readonly string[]): unknown;
|
|
47
|
+
/**
|
|
48
|
+
* Operations a MODEL must never call through MCP: their response is a secret
|
|
49
|
+
* that would land in the model's context, the transcript and client logs
|
|
50
|
+
* (Codex on #417). The CLI — a human at a keyboard — still has them.
|
|
51
|
+
*/
|
|
52
|
+
export declare const MCP_HIDDEN_OPERATIONS: ReadonlySet<string>;
|
|
53
|
+
export interface OperationOptions {
|
|
54
|
+
/** Include the operations hidden from models (the CLI passes true). */
|
|
55
|
+
includeHidden?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export declare function loadOperations(apiBaseUrl: string, fetchImpl?: typeof fetch, opts?: OperationOptions): Promise<ApiOperation[]>;
|
|
58
|
+
/** The same derivation from an already-loaded document (the API's `POST /mcp` uses it in-process). */
|
|
59
|
+
export declare function operationsFromDocument(doc: OpenApiDoc, opts?: OperationOptions): ApiOperation[];
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAC3C,qGAAqG;IACrG,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACjD,8CAA8C;IAC9C,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,gBAAgB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,WAAW,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,GAAG,SAAS,CAAC;CAClG;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACxD,UAAU,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,SAAS,CAAC;CAChE;AASD,6GAA6G;AAC7G,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,GAAE,SAAS,MAAM,EAAO,GAAG,OAAO,CAcnG;AAID;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAAgD,CAAC;AAEvG,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,OAAO,KAAa,EAC/B,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CAIzB;AAED,sGAAsG;AACtG,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,GAAE,gBAAqB,GAAG,YAAY,EAAE,CAiCnG"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP is a transport over the ONE router (blueprint §3.3): tools are derived
|
|
3
|
+
* from the live OpenAPI document, never hand-declared, so a new endpoint is a
|
|
4
|
+
* new tool (and a new CLI command) with no code here. Shared by the stdio
|
|
5
|
+
* server, the API's `POST /mcp` (W7) and the generated CLI.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Paths that are not for an API key: public visitor routes (session-token or
|
|
9
|
+
* unauthenticated), internal edge fallbacks, and the login flow. A model with a
|
|
10
|
+
* key could open a concierge session it can never continue (Codex on #418).
|
|
11
|
+
*/
|
|
12
|
+
const NOT_FOR_KEYS = /^\/(public|internal)\/|^\/v1\/auth\//;
|
|
13
|
+
/** Inline every `$ref` (against `components.schemas`) so a client needs nothing else; cycles become `{}`. */
|
|
14
|
+
export function resolveRefs(schema, doc, seen = []) {
|
|
15
|
+
if (Array.isArray(schema))
|
|
16
|
+
return schema.map((x) => resolveRefs(x, doc, seen));
|
|
17
|
+
if (!schema || typeof schema !== "object")
|
|
18
|
+
return schema;
|
|
19
|
+
const obj = schema;
|
|
20
|
+
const ref = obj["$ref"];
|
|
21
|
+
if (typeof ref === "string") {
|
|
22
|
+
const name = ref.replace(/^#\/components\/schemas\//, "");
|
|
23
|
+
if (seen.includes(name))
|
|
24
|
+
return {};
|
|
25
|
+
const target = doc.components?.schemas?.[name];
|
|
26
|
+
return target === undefined ? {} : resolveRefs(target, doc, [...seen, name]);
|
|
27
|
+
}
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const [k, v] of Object.entries(obj))
|
|
30
|
+
out[k] = resolveRefs(v, doc, seen);
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
const METHODS = ["get", "post", "put", "patch", "delete"];
|
|
34
|
+
/**
|
|
35
|
+
* Operations a MODEL must never call through MCP: their response is a secret
|
|
36
|
+
* that would land in the model's context, the transcript and client logs
|
|
37
|
+
* (Codex on #417). The CLI — a human at a keyboard — still has them.
|
|
38
|
+
*/
|
|
39
|
+
export const MCP_HIDDEN_OPERATIONS = new Set(["createApiKey", "createConnector"]);
|
|
40
|
+
export async function loadOperations(apiBaseUrl, fetchImpl = fetch, opts = {}) {
|
|
41
|
+
const res = await fetchImpl(`${apiBaseUrl}/v1/openapi.json`);
|
|
42
|
+
if (!res.ok)
|
|
43
|
+
throw new Error(`failed to load OpenAPI document: ${res.status}`);
|
|
44
|
+
return operationsFromDocument((await res.json()), opts);
|
|
45
|
+
}
|
|
46
|
+
/** The same derivation from an already-loaded document (the API's `POST /mcp` uses it in-process). */
|
|
47
|
+
export function operationsFromDocument(doc, opts = {}) {
|
|
48
|
+
const ops = [];
|
|
49
|
+
for (const [path, item] of Object.entries(doc.paths ?? {})) {
|
|
50
|
+
for (const method of METHODS) {
|
|
51
|
+
const op = item[method];
|
|
52
|
+
if (!op)
|
|
53
|
+
continue;
|
|
54
|
+
const toolName = op.operationId ??
|
|
55
|
+
`${method}_${path.replaceAll(/[{}]/g, "")}`
|
|
56
|
+
.replaceAll(/[^a-zA-Z0-9]+/g, "_")
|
|
57
|
+
.replaceAll(/_+/g, "_")
|
|
58
|
+
.replace(/^_+|_+$/g, "");
|
|
59
|
+
if (!opts.includeHidden && (MCP_HIDDEN_OPERATIONS.has(toolName) || NOT_FOR_KEYS.test(path)))
|
|
60
|
+
continue;
|
|
61
|
+
const content = op.requestBody?.content ?? {};
|
|
62
|
+
const contentTypes = Object.keys(content);
|
|
63
|
+
const bodyMediaType = contentTypes.some((t) => t.startsWith("multipart/")) ? "multipart" : contentTypes.length > 0 || op.requestBody !== undefined ? "json" : null;
|
|
64
|
+
const jsonSchema = bodyMediaType === "json" ? (content["application/json"]?.schema ?? Object.values(content)[0]?.schema) : undefined;
|
|
65
|
+
const bodySchema = jsonSchema !== undefined ? resolveRefs(jsonSchema, doc) : undefined;
|
|
66
|
+
ops.push({
|
|
67
|
+
toolName,
|
|
68
|
+
method: method.toUpperCase(),
|
|
69
|
+
path,
|
|
70
|
+
description: op.description ?? op.summary ?? `${method.toUpperCase()} ${path}`,
|
|
71
|
+
pathParams: [...path.matchAll(/\{([^}]+)\}/g)].map((m) => m[1]),
|
|
72
|
+
queryParams: (op.parameters ?? []).filter((p) => p.in === "query").map((p) => p.name),
|
|
73
|
+
hasBody: bodyMediaType !== null,
|
|
74
|
+
bodyMediaType,
|
|
75
|
+
...(bodySchema !== undefined ? { bodySchema } : {}),
|
|
76
|
+
bodyRequired: op.requestBody?.required === true,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return ops;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.js","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/**
|
|
3
|
+
* Vipcasso MCP server — one tool per API operation, executed as plain HTTP
|
|
4
|
+
* calls against the API. No business logic lives here (transport only).
|
|
5
|
+
*/
|
|
6
|
+
export declare function createVipcassoMcpServer(opts: {
|
|
7
|
+
apiBaseUrl: string;
|
|
8
|
+
apiKey?: string | undefined;
|
|
9
|
+
fetchImpl?: typeof fetch;
|
|
10
|
+
}): Promise<McpServer>;
|
|
11
|
+
/** `fields` + base64 `files` → the multipart body an upload route expects. */
|
|
12
|
+
export declare function multipartBody(fields: Record<string, string> | undefined, files: {
|
|
13
|
+
field: string;
|
|
14
|
+
filename: string;
|
|
15
|
+
content_base64: string;
|
|
16
|
+
content_type?: string | undefined;
|
|
17
|
+
}[] | undefined): FormData;
|
|
18
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B,GAAG,OAAO,CAAC,SAAS,CAAC,CAgDrB;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EAAE,GAAG,SAAS,GAAG,QAAQ,CAUvM"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { loadOperations } from "./operations.js";
|
|
4
|
+
/**
|
|
5
|
+
* Vipcasso MCP server — one tool per API operation, executed as plain HTTP
|
|
6
|
+
* calls against the API. No business logic lives here (transport only).
|
|
7
|
+
*/
|
|
8
|
+
export async function createVipcassoMcpServer(opts) {
|
|
9
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
10
|
+
const server = new McpServer({ name: "vipcasso", version: "0.0.1" });
|
|
11
|
+
const operations = await loadOperations(opts.apiBaseUrl, fetchImpl);
|
|
12
|
+
for (const op of operations) {
|
|
13
|
+
server.tool(op.toolName, op.description, {
|
|
14
|
+
path_params: z.record(z.string(), z.string()).optional(),
|
|
15
|
+
query: z.record(z.string(), z.string()).optional(),
|
|
16
|
+
body: z.unknown().optional(),
|
|
17
|
+
/** Multipart operations (file uploads): text fields… */
|
|
18
|
+
fields: z.record(z.string(), z.string()).optional(),
|
|
19
|
+
/** …and files, base64-encoded (the API declares these as multipart/form-data). */
|
|
20
|
+
files: z.array(z.object({ field: z.string(), filename: z.string(), content_base64: z.string(), content_type: z.string().optional() })).optional(),
|
|
21
|
+
}, async (args) => {
|
|
22
|
+
let path = op.path;
|
|
23
|
+
for (const p of op.pathParams) {
|
|
24
|
+
const v = args.path_params?.[p];
|
|
25
|
+
if (v === undefined)
|
|
26
|
+
throw new Error(`missing path param: ${p}`);
|
|
27
|
+
path = path.replace(`{${p}}`, encodeURIComponent(v));
|
|
28
|
+
}
|
|
29
|
+
const url = new URL(`${opts.apiBaseUrl}${path}`);
|
|
30
|
+
for (const [k, v] of Object.entries(args.query ?? {}))
|
|
31
|
+
url.searchParams.set(k, v);
|
|
32
|
+
// A multipart operation travels as FormData (the boundary comes from fetch);
|
|
33
|
+
// everything else as JSON.
|
|
34
|
+
const body = op.bodyMediaType === "multipart" ? multipartBody(args.fields, args.files) : args.body !== undefined ? JSON.stringify(args.body) : undefined;
|
|
35
|
+
const res = await fetchImpl(url.toString(), {
|
|
36
|
+
method: op.method,
|
|
37
|
+
headers: {
|
|
38
|
+
...(opts.apiKey ? { authorization: `Bearer ${opts.apiKey}` } : {}),
|
|
39
|
+
...(typeof body === "string" ? { "content-type": "application/json" } : {}),
|
|
40
|
+
},
|
|
41
|
+
...(body !== undefined ? { body } : {}),
|
|
42
|
+
});
|
|
43
|
+
const text = await res.text();
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text }],
|
|
46
|
+
isError: !res.ok,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return server;
|
|
51
|
+
}
|
|
52
|
+
/** `fields` + base64 `files` → the multipart body an upload route expects. */
|
|
53
|
+
export function multipartBody(fields, files) {
|
|
54
|
+
const fd = new FormData();
|
|
55
|
+
for (const [k, v] of Object.entries(fields ?? {}))
|
|
56
|
+
fd.set(k, v);
|
|
57
|
+
for (const f of files ?? []) {
|
|
58
|
+
const bytes = Uint8Array.from(atob(f.content_base64), (ch) => ch.charCodeAt(0));
|
|
59
|
+
const buf = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
60
|
+
// append, not set: several files may share a field (`files`), and the API reads getAll (Codex #417).
|
|
61
|
+
fd.append(f.field, new Blob([buf], f.content_type ? { type: f.content_type } : undefined), f.filename);
|
|
62
|
+
}
|
|
63
|
+
return fd;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/stdio.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":""}
|
package/dist/stdio.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { createVipcassoMcpServer } from "./server.js";
|
|
4
|
+
const apiBaseUrl = process.env["VIPCASSO_API_URL"] ?? "https://api.vipcasso.com";
|
|
5
|
+
const apiKey = process.env["VIPCASSO_API_KEY"];
|
|
6
|
+
const server = await createVipcassoMcpServer({ apiBaseUrl, apiKey });
|
|
7
|
+
await server.connect(new StdioServerTransport());
|
|
8
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,0BAA0B,CAAC;AACjF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAE/C,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;AACrE,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vipcasso/mcp",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./operations": {
|
|
12
|
+
"types": "./dist/operations.d.ts",
|
|
13
|
+
"default": "./dist/operations.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"vipcasso-mcp": "./dist/stdio.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
21
|
+
"zod": "4.4.3"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "26.1.1",
|
|
25
|
+
"typescript": "6.0.3",
|
|
26
|
+
"vitest": "4.1.11",
|
|
27
|
+
"@vitest/coverage-v8": "4.1.11"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"license": "UNLICENSED",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/AspynAI/vipcasso.git",
|
|
39
|
+
"directory": "packages/mcp"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc -p tsconfig.json",
|
|
43
|
+
"typecheck": "tsc -p tsconfig.json --noEmit false --emitDeclarationOnly",
|
|
44
|
+
"lint": "eslint src",
|
|
45
|
+
"test": "vitest run"
|
|
46
|
+
}
|
|
6
47
|
}
|
package/README.md
DELETED