@reneturcios/ballpark 0.0.0-stage → 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 +94 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +102 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +39 -0
- package/dist/mcp.js +234 -0
- package/dist/mcp.js.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/upstream.d.ts +52 -0
- package/dist/upstream.js +167 -0
- package/dist/upstream.js.map +1 -0
- package/package.json +1 -6
- package/server.json +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rene Turcios
|
|
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
CHANGED
|
@@ -1,3 +1,95 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ballpark
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A forwarding client for the published Dribba MCP remote.
|
|
4
|
+
Dribba is a product studio; its remote MCP server exposes
|
|
5
|
+
public studio data — its services, its case studies, a
|
|
6
|
+
ballpark budget calculator, structured company facts, and
|
|
7
|
+
a contact-request tool. There is no installable package
|
|
8
|
+
for that remote, so ballpark gives it a local stdio MCP
|
|
9
|
+
server and a small CLI: `tools/list` is answered locally
|
|
10
|
+
from the verbatim live capture of the remote, and every
|
|
11
|
+
`tools/call` is forwarded to the remote over streamable
|
|
12
|
+
HTTP.
|
|
13
|
+
|
|
14
|
+
The upstream result passes through verbatim, including
|
|
15
|
+
`structuredContent` and any `isError` flag. Failures on
|
|
16
|
+
the way there or back are reported as an error result
|
|
17
|
+
whose text starts with `ballpark error: `.
|
|
18
|
+
|
|
19
|
+
## Upstream and the override
|
|
20
|
+
|
|
21
|
+
- Upstream: `https://dribba.com/mcp` (pinned).
|
|
22
|
+
- Override: set `DRIBBA_MCP_URL` to point the client at a
|
|
23
|
+
different endpoint. This override is a reconstruction:
|
|
24
|
+
no override is published for the remote-only original.
|
|
25
|
+
- The client handshake is `initialize` (protocol version
|
|
26
|
+
`2025-03-26`, client `ballpark` / `0.1.0`), then
|
|
27
|
+
`notifications/initialized`, then `tools/call`. When the
|
|
28
|
+
upstream issues an `Mcp-Session-Id`, it is honoured on
|
|
29
|
+
every later request. Responses may be plain JSON or an
|
|
30
|
+
SSE stream.
|
|
31
|
+
- Argument validation is local: an unknown tool or
|
|
32
|
+
malformed arguments fail before anything is forwarded.
|
|
33
|
+
`submit_contact_request` is forwarded like the other
|
|
34
|
+
tools; its captured description — which asks for
|
|
35
|
+
explicit user confirmation of the exact name, email and
|
|
36
|
+
message before calling — is served verbatim, and this
|
|
37
|
+
rebuild adds no gating of its own.
|
|
38
|
+
|
|
39
|
+
## Install and run
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx -y @reneturcios/ballpark mcp # stdio MCP server
|
|
43
|
+
npx -y @reneturcios/ballpark --version # 0.1.0
|
|
44
|
+
npx -y @reneturcios/ballpark list_services '{"limit":3}'
|
|
45
|
+
npx -y @reneturcios/ballpark estimate_project '{"platforms":["ios","web"],"complexity":"standard"}'
|
|
46
|
+
npx -y @reneturcios/ballpark list_projects '{"industry":"fintech"}'
|
|
47
|
+
npx -y @reneturcios/ballpark company_facts '{"fields":["offices","distinctions"]}'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Each tool subcommand takes one JSON argument string and
|
|
51
|
+
prints the forwarded result. Exit codes: 0 on success,
|
|
52
|
+
1 on an error result, 2 on a usage or validation error.
|
|
53
|
+
|
|
54
|
+
## MCP client config
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"ballpark": {
|
|
60
|
+
"command": "npx",
|
|
61
|
+
"args": ["-y", "@reneturcios/ballpark", "mcp"]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Docker
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
docker run -i ghcr.io/cloudcorprecords/ballpark # stdio MCP server
|
|
71
|
+
docker run --rm ghcr.io/cloudcorprecords/ballpark --version # CLI
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Tools
|
|
75
|
+
|
|
76
|
+
| Tool | What it does |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `list_services` | List Dribba's services with a one-line summary and URL. |
|
|
79
|
+
| `estimate_project` | Ballpark budget and range for an app/product, mirroring dribba.com's public calculator. Minimum project budget is €30,000. Requires `platforms`. |
|
|
80
|
+
| `list_projects` | List Dribba's case studies (slug, title, industry). |
|
|
81
|
+
| `company_facts` | Structured facts about Dribba: positioning, offices, team, distinctions, clients. |
|
|
82
|
+
| `submit_contact_request` | Submit a real project inquiry to Dribba on behalf of the user. This sends an email and creates a lead — ONLY call it after the user has explicitly confirmed the exact name, email and message to be sent. Dribba replies within 1h. Rate-limited per client. |
|
|
83
|
+
|
|
84
|
+
## Development
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm install
|
|
88
|
+
npm run build # tsc -> dist/
|
|
89
|
+
npm test # tsx --test test/*.test.ts (fake fetch only, no network)
|
|
90
|
+
npm run dev # run the CLI from source
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT — Copyright (c) 2026 Rene Turcios.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ballpark CLI.
|
|
4
|
+
*
|
|
5
|
+
* ballpark list_services '<json>'
|
|
6
|
+
* ballpark estimate_project '<json>'
|
|
7
|
+
* ballpark list_projects '<json>'
|
|
8
|
+
* ballpark company_facts '<json>'
|
|
9
|
+
* ballpark submit_contact_request '<json>'
|
|
10
|
+
* ballpark mcp
|
|
11
|
+
* ballpark --version
|
|
12
|
+
*
|
|
13
|
+
* Each tool subcommand takes one JSON argument string with
|
|
14
|
+
* the tool's arguments, forwards the call upstream like
|
|
15
|
+
* the MCP path, and prints the forwarded result content.
|
|
16
|
+
* Exit codes: 0 success, 1 on an isError result, 2 usage
|
|
17
|
+
* error (unknown subcommand, non-JSON argument, or
|
|
18
|
+
* arguments that fail the same validation the MCP
|
|
19
|
+
* handler applies).
|
|
20
|
+
*/
|
|
21
|
+
import { callTool, VERSION } from "./upstream.js";
|
|
22
|
+
const TOOL_NAMES = [
|
|
23
|
+
"list_services",
|
|
24
|
+
"estimate_project",
|
|
25
|
+
"list_projects",
|
|
26
|
+
"company_facts",
|
|
27
|
+
"submit_contact_request",
|
|
28
|
+
];
|
|
29
|
+
function usage() {
|
|
30
|
+
console.error(`Usage:
|
|
31
|
+
ballpark <tool> '<json-args>' one of: ${TOOL_NAMES.join(", ")}
|
|
32
|
+
ballpark mcp
|
|
33
|
+
ballpark --version`);
|
|
34
|
+
process.exit(2);
|
|
35
|
+
}
|
|
36
|
+
function renderContent(result) {
|
|
37
|
+
if (result.structuredContent !== undefined) {
|
|
38
|
+
return JSON.stringify(result.structuredContent);
|
|
39
|
+
}
|
|
40
|
+
const content = result.content;
|
|
41
|
+
if (Array.isArray(content)) {
|
|
42
|
+
return content
|
|
43
|
+
.map((item) => {
|
|
44
|
+
if (item !== null &&
|
|
45
|
+
typeof item === "object" &&
|
|
46
|
+
item.type === "text" &&
|
|
47
|
+
typeof item.text === "string") {
|
|
48
|
+
return item.text;
|
|
49
|
+
}
|
|
50
|
+
return JSON.stringify(item);
|
|
51
|
+
})
|
|
52
|
+
.join("\n");
|
|
53
|
+
}
|
|
54
|
+
return typeof content === "string" ? content : JSON.stringify(result);
|
|
55
|
+
}
|
|
56
|
+
async function main() {
|
|
57
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
58
|
+
if (cmd === "--version" || cmd === "-v") {
|
|
59
|
+
console.log(VERSION);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (cmd === "mcp") {
|
|
63
|
+
if (rest.length !== 0)
|
|
64
|
+
usage();
|
|
65
|
+
const { startBallparkServer } = await import("./mcp.js");
|
|
66
|
+
await startBallparkServer();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!cmd || !TOOL_NAMES.includes(cmd))
|
|
70
|
+
usage();
|
|
71
|
+
if (rest.length > 1)
|
|
72
|
+
usage();
|
|
73
|
+
let args = {};
|
|
74
|
+
if (rest.length === 1) {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(rest[0]);
|
|
77
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
78
|
+
usage();
|
|
79
|
+
args = parsed;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
console.error("error: argument must be a JSON object string");
|
|
83
|
+
process.exit(2);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const { validateToolArgs } = await import("./mcp.js");
|
|
87
|
+
try {
|
|
88
|
+
args = validateToolArgs(cmd, args);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
console.error(`error: ${err instanceof Error ? err.message : String(err)}`);
|
|
92
|
+
process.exit(2);
|
|
93
|
+
}
|
|
94
|
+
const result = await callTool(cmd, args);
|
|
95
|
+
if (result.isError) {
|
|
96
|
+
console.error(`error: ${renderContent(result)}`);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
console.log(renderContent(result));
|
|
100
|
+
}
|
|
101
|
+
void main();
|
|
102
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ballpark MCP server. Tools: list_services,
|
|
3
|
+
* estimate_project, list_projects, company_facts,
|
|
4
|
+
* submit_contact_request.
|
|
5
|
+
*
|
|
6
|
+
* Why the low-level Server instead of McpServer: the
|
|
7
|
+
* high-level helper converts zod schemas to JSON Schema
|
|
8
|
+
* and injects keys that are not in this tool set's
|
|
9
|
+
* captured spec, which breaks exact tool-list/schema
|
|
10
|
+
* parity with the live capture. This file serves
|
|
11
|
+
* tools/list from the explicit literals below — the
|
|
12
|
+
* verbatim tool objects from the remote's live
|
|
13
|
+
* tools/list capture — and forwards every tools/call
|
|
14
|
+
* upstream.
|
|
15
|
+
*
|
|
16
|
+
* The handler validates tools/call arguments itself:
|
|
17
|
+
* an unknown tool name or malformed arguments (missing
|
|
18
|
+
* required fields, wrong types, out-of-range values,
|
|
19
|
+
* unexpected properties where the captured schema sets
|
|
20
|
+
* additionalProperties: false) raise McpError with
|
|
21
|
+
* ErrorCode.InvalidParams, and nothing is forwarded.
|
|
22
|
+
* Valid calls are forwarded and the upstream result is
|
|
23
|
+
* returned verbatim, including structuredContent and
|
|
24
|
+
* any isError flag.
|
|
25
|
+
*/
|
|
26
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
27
|
+
import { type BallparkClient } from "./upstream.js";
|
|
28
|
+
import type { ToolArgs, ToolDef } from "./types.js";
|
|
29
|
+
export declare const TOOL_DEFS: ToolDef[];
|
|
30
|
+
export declare const TOOL_NAMES: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Validate tools/call arguments against the captured
|
|
33
|
+
* literal schema for `name`. Returns the argument object
|
|
34
|
+
* to forward. Throws McpError(InvalidParams) for an
|
|
35
|
+
* unknown tool or any malformed argument set.
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateToolArgs(name: string, args: unknown): ToolArgs;
|
|
38
|
+
export declare function createBallparkServer(client?: BallparkClient): Server;
|
|
39
|
+
export declare function startBallparkServer(client?: BallparkClient): Promise<void>;
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ballpark MCP server. Tools: list_services,
|
|
3
|
+
* estimate_project, list_projects, company_facts,
|
|
4
|
+
* submit_contact_request.
|
|
5
|
+
*
|
|
6
|
+
* Why the low-level Server instead of McpServer: the
|
|
7
|
+
* high-level helper converts zod schemas to JSON Schema
|
|
8
|
+
* and injects keys that are not in this tool set's
|
|
9
|
+
* captured spec, which breaks exact tool-list/schema
|
|
10
|
+
* parity with the live capture. This file serves
|
|
11
|
+
* tools/list from the explicit literals below — the
|
|
12
|
+
* verbatim tool objects from the remote's live
|
|
13
|
+
* tools/list capture — and forwards every tools/call
|
|
14
|
+
* upstream.
|
|
15
|
+
*
|
|
16
|
+
* The handler validates tools/call arguments itself:
|
|
17
|
+
* an unknown tool name or malformed arguments (missing
|
|
18
|
+
* required fields, wrong types, out-of-range values,
|
|
19
|
+
* unexpected properties where the captured schema sets
|
|
20
|
+
* additionalProperties: false) raise McpError with
|
|
21
|
+
* ErrorCode.InvalidParams, and nothing is forwarded.
|
|
22
|
+
* Valid calls are forwarded and the upstream result is
|
|
23
|
+
* returned verbatim, including structuredContent and
|
|
24
|
+
* any isError flag.
|
|
25
|
+
*/
|
|
26
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
27
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
28
|
+
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
29
|
+
import { createClient, VERSION } from "./upstream.js";
|
|
30
|
+
export const TOOL_DEFS = [
|
|
31
|
+
{
|
|
32
|
+
name: "list_services",
|
|
33
|
+
description: "List Dribba's services with a one-line summary and URL.",
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
limit: {
|
|
38
|
+
type: "integer",
|
|
39
|
+
minimum: 1,
|
|
40
|
+
maximum: 50,
|
|
41
|
+
description: "Maximum number of services to return. Omit for all of them.",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: [],
|
|
45
|
+
additionalProperties: false,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "estimate_project",
|
|
50
|
+
description: "Ballpark budget and range for an app/product, mirroring dribba.com's public calculator. Minimum project budget is €30,000.",
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: {
|
|
54
|
+
platforms: {
|
|
55
|
+
type: "array",
|
|
56
|
+
items: {
|
|
57
|
+
type: "string",
|
|
58
|
+
enum: ["ios", "android", "web", "desktop"],
|
|
59
|
+
},
|
|
60
|
+
description: "At least one target platform.",
|
|
61
|
+
},
|
|
62
|
+
complexity: {
|
|
63
|
+
type: "string",
|
|
64
|
+
enum: ["mvp", "standard", "complex"],
|
|
65
|
+
},
|
|
66
|
+
design: {
|
|
67
|
+
type: "string",
|
|
68
|
+
enum: ["basic", "custom", "premium"],
|
|
69
|
+
},
|
|
70
|
+
timeline: {
|
|
71
|
+
type: "string",
|
|
72
|
+
enum: ["rush", "normal", "relaxed"],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
required: ["platforms"],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "list_projects",
|
|
80
|
+
description: "List Dribba's case studies (slug, title, industry).",
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
industry: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description: "Case-insensitive substring match on the industry, e.g. \"fintech\". Omit for all industries.",
|
|
87
|
+
},
|
|
88
|
+
limit: {
|
|
89
|
+
type: "integer",
|
|
90
|
+
minimum: 1,
|
|
91
|
+
maximum: 50,
|
|
92
|
+
description: "Maximum number of case studies to return.",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
required: [],
|
|
96
|
+
additionalProperties: false,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "company_facts",
|
|
101
|
+
description: "Structured facts about Dribba: positioning, offices, team, distinctions, clients.",
|
|
102
|
+
inputSchema: {
|
|
103
|
+
type: "object",
|
|
104
|
+
properties: {
|
|
105
|
+
fields: {
|
|
106
|
+
type: "array",
|
|
107
|
+
items: {
|
|
108
|
+
type: "string",
|
|
109
|
+
},
|
|
110
|
+
description: "Subset of fact keys to return (e.g. [\"offices\",\"distinctions\"]). Omit for every fact.",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
required: [],
|
|
114
|
+
additionalProperties: false,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "submit_contact_request",
|
|
119
|
+
description: "Submit a real project inquiry to Dribba on behalf of the user. This sends an email and creates a lead — ONLY call it after the user has explicitly confirmed the exact name, email and message to be sent. Dribba replies within 1h. Rate-limited per client.",
|
|
120
|
+
inputSchema: {
|
|
121
|
+
type: "object",
|
|
122
|
+
properties: {
|
|
123
|
+
name: {
|
|
124
|
+
type: "string",
|
|
125
|
+
description: "Full name of the person making the inquiry.",
|
|
126
|
+
},
|
|
127
|
+
email: {
|
|
128
|
+
type: "string",
|
|
129
|
+
description: "Email address Dribba should reply to.",
|
|
130
|
+
},
|
|
131
|
+
message: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "The inquiry, confirmed by the user.",
|
|
134
|
+
},
|
|
135
|
+
company: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Company name (optional).",
|
|
138
|
+
},
|
|
139
|
+
budget: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "Approximate budget range, e.g. \"30-60k EUR\" (optional).",
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
required: ["name", "email", "message"],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
export const TOOL_NAMES = TOOL_DEFS.map((t) => t.name);
|
|
149
|
+
function invalid(message) {
|
|
150
|
+
return new McpError(ErrorCode.InvalidParams, message);
|
|
151
|
+
}
|
|
152
|
+
function checkValue(tool, key, value, schema) {
|
|
153
|
+
const type = schema.type;
|
|
154
|
+
if (type === "string") {
|
|
155
|
+
if (typeof value !== "string")
|
|
156
|
+
throw invalid(`${tool}: argument "${key}" must be a string`);
|
|
157
|
+
}
|
|
158
|
+
else if (type === "integer") {
|
|
159
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
160
|
+
throw invalid(`${tool}: argument "${key}" must be an integer`);
|
|
161
|
+
}
|
|
162
|
+
if (typeof schema.minimum === "number" && value < schema.minimum) {
|
|
163
|
+
throw invalid(`${tool}: argument "${key}" must be >= ${schema.minimum}`);
|
|
164
|
+
}
|
|
165
|
+
if (typeof schema.maximum === "number" && value > schema.maximum) {
|
|
166
|
+
throw invalid(`${tool}: argument "${key}" must be <= ${schema.maximum}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (type === "array") {
|
|
170
|
+
if (!Array.isArray(value))
|
|
171
|
+
throw invalid(`${tool}: argument "${key}" must be an array`);
|
|
172
|
+
const items = schema.items;
|
|
173
|
+
if (items) {
|
|
174
|
+
for (const item of value)
|
|
175
|
+
checkValue(tool, key, item, items);
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (Array.isArray(schema.enum) && !schema.enum.includes(value)) {
|
|
180
|
+
throw invalid(`${tool}: argument "${key}" must be one of ${schema.enum.join(", ")}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Validate tools/call arguments against the captured
|
|
185
|
+
* literal schema for `name`. Returns the argument object
|
|
186
|
+
* to forward. Throws McpError(InvalidParams) for an
|
|
187
|
+
* unknown tool or any malformed argument set.
|
|
188
|
+
*/
|
|
189
|
+
export function validateToolArgs(name, args) {
|
|
190
|
+
const def = TOOL_DEFS.find((t) => t.name === name);
|
|
191
|
+
if (!def)
|
|
192
|
+
throw invalid(`Unknown tool: ${name}`);
|
|
193
|
+
const value = args ?? {};
|
|
194
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
195
|
+
throw invalid(`${name}: arguments must be an object`);
|
|
196
|
+
}
|
|
197
|
+
const obj = value;
|
|
198
|
+
const schema = def.inputSchema;
|
|
199
|
+
const properties = schema.properties ?? {};
|
|
200
|
+
for (const req of schema.required ?? []) {
|
|
201
|
+
if (obj[req] === undefined || obj[req] === null) {
|
|
202
|
+
throw invalid(`${name}: missing required argument "${req}"`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (schema.additionalProperties === false) {
|
|
206
|
+
for (const key of Object.keys(obj)) {
|
|
207
|
+
if (!(key in properties))
|
|
208
|
+
throw invalid(`${name}: unexpected argument "${key}"`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
212
|
+
const propSchema = properties[key];
|
|
213
|
+
if (propSchema && val !== undefined)
|
|
214
|
+
checkValue(name, key, val, propSchema);
|
|
215
|
+
}
|
|
216
|
+
return obj;
|
|
217
|
+
}
|
|
218
|
+
export function createBallparkServer(client = createClient()) {
|
|
219
|
+
const server = new Server({ name: "ballpark", version: VERSION }, { capabilities: { tools: {} } });
|
|
220
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOL_DEFS }));
|
|
221
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
222
|
+
const { name, arguments: args } = request.params;
|
|
223
|
+
const validArgs = validateToolArgs(name, args ?? {});
|
|
224
|
+
const result = await client.callTool(name, validArgs);
|
|
225
|
+
// Upstream result passes through verbatim.
|
|
226
|
+
return result;
|
|
227
|
+
});
|
|
228
|
+
return server;
|
|
229
|
+
}
|
|
230
|
+
export async function startBallparkServer(client) {
|
|
231
|
+
const server = createBallparkServer(client);
|
|
232
|
+
await server.connect(new StdioServerTransport());
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ballpark types.
|
|
3
|
+
*
|
|
4
|
+
* A forwarding client for the published Dribba MCP remote.
|
|
5
|
+
* tools/list is served locally from literal definitions;
|
|
6
|
+
* tools/call is forwarded upstream and the upstream result
|
|
7
|
+
* passes through verbatim.
|
|
8
|
+
*/
|
|
9
|
+
/** A tool's arguments, as decoded JSON. */
|
|
10
|
+
export type ToolArgs = Record<string, unknown>;
|
|
11
|
+
/** A JSON Schema object, as captured in the tools/list literal. */
|
|
12
|
+
export type JsonSchema = Record<string, unknown>;
|
|
13
|
+
/** One tool definition, exactly as served by tools/list. */
|
|
14
|
+
export interface ToolDef {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
inputSchema: JsonSchema;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The result shape shared by the MCP handler and the CLI.
|
|
21
|
+
* Extra keys from upstream (for example structuredContent
|
|
22
|
+
* or _meta) are preserved verbatim, hence the index
|
|
23
|
+
* signature.
|
|
24
|
+
*/
|
|
25
|
+
export interface ToolResult {
|
|
26
|
+
content?: unknown;
|
|
27
|
+
structuredContent?: Record<string, unknown>;
|
|
28
|
+
isError?: boolean;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
/** The minimal slice of a fetch Response this client relies on. */
|
|
32
|
+
export interface FetchResponseLike {
|
|
33
|
+
ok: boolean;
|
|
34
|
+
status: number;
|
|
35
|
+
headers: {
|
|
36
|
+
get(name: string): string | null;
|
|
37
|
+
};
|
|
38
|
+
text(): Promise<string>;
|
|
39
|
+
}
|
|
40
|
+
/** Injectable fetch, so tests never touch the live network. */
|
|
41
|
+
export type FetchFn = (url: string, init?: {
|
|
42
|
+
method?: string;
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
body?: string;
|
|
45
|
+
signal?: AbortSignal;
|
|
46
|
+
}) => Promise<FetchResponseLike>;
|
|
47
|
+
/** Injectable dependencies for the upstream client. */
|
|
48
|
+
export interface UpstreamDeps {
|
|
49
|
+
fetchFn?: FetchFn;
|
|
50
|
+
url?: string;
|
|
51
|
+
env?: Record<string, string | undefined>;
|
|
52
|
+
timeoutMs?: number;
|
|
53
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ballpark types.
|
|
3
|
+
*
|
|
4
|
+
* A forwarding client for the published Dribba MCP remote.
|
|
5
|
+
* tools/list is served locally from literal definitions;
|
|
6
|
+
* tools/call is forwarded upstream and the upstream result
|
|
7
|
+
* passes through verbatim.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ballpark core: a forwarding client for the published
|
|
3
|
+
* Dribba MCP remote at https://dribba.com/mcp.
|
|
4
|
+
*
|
|
5
|
+
* The endpoint is pinned by the spec. An override via the
|
|
6
|
+
* DRIBBA_MCP_URL environment variable is a labelled
|
|
7
|
+
* reconstruction: no override is published for this
|
|
8
|
+
* remote-only server.
|
|
9
|
+
*
|
|
10
|
+
* Wire protocol (streamable HTTP, JSON-RPC):
|
|
11
|
+
* initialize (protocolVersion "2025-03-26", clientInfo
|
|
12
|
+
* { name: "ballpark", version: VERSION })
|
|
13
|
+
* -> notifications/initialized -> tools/call
|
|
14
|
+
* The session is established lazily on the first forwarded
|
|
15
|
+
* call and reused for the client's lifetime. When the
|
|
16
|
+
* upstream issues an Mcp-Session-Id response header it is
|
|
17
|
+
* captured and sent on every later request.
|
|
18
|
+
*
|
|
19
|
+
* Responses may be plain JSON or SSE (`data:` lines); the
|
|
20
|
+
* JSON-RPC message whose `id` matches the request is the
|
|
21
|
+
* answer. An upstream `result` passes through verbatim
|
|
22
|
+
* (content, structuredContent, isError and any other keys).
|
|
23
|
+
* Every failure — HTTP error, JSON-RPC error, malformed
|
|
24
|
+
* response, or a throwing fetch — becomes an isError result
|
|
25
|
+
* whose text starts with "ballpark error: " (this rebuild's
|
|
26
|
+
* own error rendering, a labelled reconstruction).
|
|
27
|
+
*
|
|
28
|
+
* All upstream access goes through an injectable fetch, so
|
|
29
|
+
* tests use a fake fetch only and never touch the network.
|
|
30
|
+
*/
|
|
31
|
+
import type { ToolArgs, ToolResult, UpstreamDeps } from "./types.js";
|
|
32
|
+
export declare const VERSION = "0.1.0";
|
|
33
|
+
export declare const DEFAULT_UPSTREAM_URL = "https://dribba.com/mcp";
|
|
34
|
+
/** Parse a response body that is plain JSON or an SSE stream. */
|
|
35
|
+
export declare function parseRpcMessage(body: string, wantId: number): Record<string, unknown> | null;
|
|
36
|
+
export declare class BallparkClient {
|
|
37
|
+
private readonly fetchFn;
|
|
38
|
+
private readonly url;
|
|
39
|
+
private readonly timeoutMs;
|
|
40
|
+
private sessionId;
|
|
41
|
+
private sessionPromise;
|
|
42
|
+
private nextId;
|
|
43
|
+
constructor(deps?: UpstreamDeps);
|
|
44
|
+
get upstreamUrl(): string;
|
|
45
|
+
private post;
|
|
46
|
+
private ensureSession;
|
|
47
|
+
/** Forward one tools/call upstream; failures become "ballpark error: ..." results. */
|
|
48
|
+
callTool(name: string, args: ToolArgs): Promise<ToolResult>;
|
|
49
|
+
}
|
|
50
|
+
export declare function createClient(deps?: UpstreamDeps): BallparkClient;
|
|
51
|
+
/** Convenience one-shot forward used by the CLI. */
|
|
52
|
+
export declare function callTool(name: string, args: ToolArgs, deps?: UpstreamDeps): Promise<ToolResult>;
|
package/dist/upstream.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
export const VERSION = "0.1.0";
|
|
2
|
+
export const DEFAULT_UPSTREAM_URL = "https://dribba.com/mcp";
|
|
3
|
+
const PROTOCOL_VERSION = "2025-03-26";
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 60000;
|
|
5
|
+
function errorResult(message) {
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: "text", text: `ballpark error: ${message}` }],
|
|
8
|
+
isError: true,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** Parse a response body that is plain JSON or an SSE stream. */
|
|
12
|
+
export function parseRpcMessage(body, wantId) {
|
|
13
|
+
const trimmed = body.trim();
|
|
14
|
+
if (!trimmed)
|
|
15
|
+
return null;
|
|
16
|
+
const candidates = [];
|
|
17
|
+
if (trimmed.startsWith("{")) {
|
|
18
|
+
try {
|
|
19
|
+
candidates.push(JSON.parse(trimmed));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// fall through to the SSE scan below
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (candidates.length === 0) {
|
|
26
|
+
for (const line of trimmed.split(/\r?\n/)) {
|
|
27
|
+
const t = line.trim();
|
|
28
|
+
if (!t.startsWith("data:"))
|
|
29
|
+
continue;
|
|
30
|
+
const payload = t.slice("data:".length).trim();
|
|
31
|
+
if (!payload || payload === "[DONE]")
|
|
32
|
+
continue;
|
|
33
|
+
try {
|
|
34
|
+
candidates.push(JSON.parse(payload));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// ignore non-JSON data lines
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
let fallback = null;
|
|
42
|
+
for (const c of candidates) {
|
|
43
|
+
if (c === null || typeof c !== "object" || Array.isArray(c))
|
|
44
|
+
continue;
|
|
45
|
+
const msg = c;
|
|
46
|
+
if (msg.id === wantId)
|
|
47
|
+
return msg;
|
|
48
|
+
if (fallback === null && ("result" in msg || "error" in msg))
|
|
49
|
+
fallback = msg;
|
|
50
|
+
}
|
|
51
|
+
return fallback;
|
|
52
|
+
}
|
|
53
|
+
export class BallparkClient {
|
|
54
|
+
fetchFn;
|
|
55
|
+
url;
|
|
56
|
+
timeoutMs;
|
|
57
|
+
sessionId = null;
|
|
58
|
+
sessionPromise = null;
|
|
59
|
+
nextId = 1;
|
|
60
|
+
constructor(deps = {}) {
|
|
61
|
+
const env = deps.env ?? process.env;
|
|
62
|
+
this.fetchFn = deps.fetchFn ?? ((url, init) => fetch(url, init));
|
|
63
|
+
// DRIBBA_MCP_URL override: labelled reconstruction.
|
|
64
|
+
this.url = deps.url ?? env.DRIBBA_MCP_URL ?? DEFAULT_UPSTREAM_URL;
|
|
65
|
+
const envTimeout = env.DRIBBA_TIMEOUT_MS ? Number(env.DRIBBA_TIMEOUT_MS) : NaN;
|
|
66
|
+
this.timeoutMs =
|
|
67
|
+
deps.timeoutMs ?? (Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : DEFAULT_TIMEOUT_MS);
|
|
68
|
+
}
|
|
69
|
+
get upstreamUrl() {
|
|
70
|
+
return this.url;
|
|
71
|
+
}
|
|
72
|
+
async post(payload, wantResponse) {
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
75
|
+
try {
|
|
76
|
+
const headers = {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
Accept: "application/json, text/event-stream",
|
|
79
|
+
};
|
|
80
|
+
if (this.sessionId)
|
|
81
|
+
headers["Mcp-Session-Id"] = this.sessionId;
|
|
82
|
+
const res = await this.fetchFn(this.url, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers,
|
|
85
|
+
body: JSON.stringify(payload),
|
|
86
|
+
signal: controller.signal,
|
|
87
|
+
});
|
|
88
|
+
const issued = res.headers?.get?.("mcp-session-id") ?? res.headers?.get?.("Mcp-Session-Id") ?? null;
|
|
89
|
+
if (issued)
|
|
90
|
+
this.sessionId = issued;
|
|
91
|
+
const text = await res.text();
|
|
92
|
+
if (!res.ok) {
|
|
93
|
+
throw new Error(`upstream HTTP ${res.status}`);
|
|
94
|
+
}
|
|
95
|
+
if (!wantResponse)
|
|
96
|
+
return { msg: null, status: res.status, ok: res.ok };
|
|
97
|
+
const id = payload.id ?? 0;
|
|
98
|
+
return { msg: parseRpcMessage(text, id), status: res.status, ok: res.ok };
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
ensureSession() {
|
|
105
|
+
if (!this.sessionPromise) {
|
|
106
|
+
this.sessionPromise = (async () => {
|
|
107
|
+
const id = this.nextId++;
|
|
108
|
+
const { msg } = await this.post({
|
|
109
|
+
jsonrpc: "2.0",
|
|
110
|
+
id,
|
|
111
|
+
method: "initialize",
|
|
112
|
+
params: {
|
|
113
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
114
|
+
capabilities: {},
|
|
115
|
+
clientInfo: { name: "ballpark", version: VERSION },
|
|
116
|
+
},
|
|
117
|
+
}, true);
|
|
118
|
+
if (!msg)
|
|
119
|
+
throw new Error("malformed response");
|
|
120
|
+
if (msg.error) {
|
|
121
|
+
const e = msg.error;
|
|
122
|
+
throw new Error(typeof e.message === "string" ? e.message : "upstream error");
|
|
123
|
+
}
|
|
124
|
+
if (!("result" in msg))
|
|
125
|
+
throw new Error("malformed response");
|
|
126
|
+
await this.post({ jsonrpc: "2.0", method: "notifications/initialized" }, false);
|
|
127
|
+
return null;
|
|
128
|
+
})();
|
|
129
|
+
// A failed handshake must not poison later calls.
|
|
130
|
+
this.sessionPromise.catch(() => {
|
|
131
|
+
this.sessionPromise = null;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return this.sessionPromise;
|
|
135
|
+
}
|
|
136
|
+
/** Forward one tools/call upstream; failures become "ballpark error: ..." results. */
|
|
137
|
+
async callTool(name, args) {
|
|
138
|
+
try {
|
|
139
|
+
await this.ensureSession();
|
|
140
|
+
const id = this.nextId++;
|
|
141
|
+
const { msg } = await this.post({ jsonrpc: "2.0", id, method: "tools/call", params: { name, arguments: args } }, true);
|
|
142
|
+
if (!msg)
|
|
143
|
+
return errorResult("malformed response");
|
|
144
|
+
if (msg.error) {
|
|
145
|
+
const e = msg.error;
|
|
146
|
+
return errorResult(typeof e.message === "string" ? e.message : "upstream error");
|
|
147
|
+
}
|
|
148
|
+
if (!("result" in msg) || msg.result === null || typeof msg.result !== "object") {
|
|
149
|
+
return errorResult("malformed response");
|
|
150
|
+
}
|
|
151
|
+
// Upstream result passes through verbatim.
|
|
152
|
+
return msg.result;
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
156
|
+
return errorResult(message);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export function createClient(deps = {}) {
|
|
161
|
+
return new BallparkClient(deps);
|
|
162
|
+
}
|
|
163
|
+
/** Convenience one-shot forward used by the CLI. */
|
|
164
|
+
export async function callTool(name, args, deps = {}) {
|
|
165
|
+
return createClient(deps).callTool(name, args);
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=upstream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream.js","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@reneturcios/ballpark",
|
|
3
|
-
"version": "0.0.0-stage",
|
|
4
|
-
"stub": true,
|
|
5
|
-
"description": "Temporary package placeholder for staged publishing"
|
|
6
|
-
}
|
|
1
|
+
{"bin":{"ballpark":"dist/cli.js"},"dependencies":{"@modelcontextprotocol/sdk":"^1","zod":"^4"},"description":"Forwarding client for the published Dribba MCP remote: services, case studies, budget estimates, company facts and contact requests, served locally for tools/list and forwarded for tools/call. One bin serves a small CLI and a stdio MCP server.","devDependencies":{"@types/node":"^20","tsx":"^4","typescript":"^5"},"engines":{"node":">=20"},"files":["dist","server.json"],"homepage":"https://github.com/CloudCorpRecords/ballpark#readme","license":"MIT","mcpName":"io.github.CloudCorpRecords/ballpark","name":"@reneturcios/ballpark","private":false,"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/CloudCorpRecords/ballpark.git"},"scripts":{"build":"tsc","dev":"tsx src/cli.ts","test":"tsx --test test/*.test.ts"},"type":"module","version":"0.1.0"}
|
package/server.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json","description":"Forwarding client for Dribba studio data: services, case studies, budget estimates, contact.","name":"io.github.CloudCorpRecords/ballpark","packages":[{"identifier":"@reneturcios/ballpark","packageArguments":[{"type":"positional","value":"mcp"}],"registryBaseUrl":"https://registry.npmjs.org","registryType":"npm","runtimeHint":"npx","transport":{"type":"stdio"},"version":"0.1.0"},{"identifier":"ghcr.io/cloudcorprecords/ballpark:0.1.0","packageArguments":[{"type":"positional","value":"mcp"}],"registryType":"oci","runtimeArguments":[{"name":"--rm","type":"named"},{"name":"-i","type":"named"}],"runtimeHint":"docker","transport":{"type":"stdio"}}],"repository":{"source":"github","url":"https://github.com/CloudCorpRecords/ballpark"},"version":"0.1.0"}
|