Skip to content

Commit 07af2c8

Browse files
committed
sync
1 parent 52065ca commit 07af2c8

File tree

7 files changed

+171
-37
lines changed

7 files changed

+171
-37
lines changed

bun.lock

Lines changed: 13 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/opencontrol/package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@
1111
},
1212
"exports": {
1313
".": "./dist/index.js",
14-
"./*": "./dist/*"
14+
"./*": "./dist/*.js"
1515
},
1616
"dependencies": {
1717
"@modelcontextprotocol/sdk": "1.6.1",
1818
"@tsconfig/bun": "1.0.7",
19-
"hono": "4.7.4"
19+
"hono": "4.7.4",
20+
"zod": "3.24.2",
21+
"zod-to-json-schema": "3.24.3"
22+
},
23+
"devDependencies": {
24+
"@standard-schema/spec": "1.0.0"
2025
}
2126
}

packages/opencontrol/src/index.ts

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,28 @@
1-
import { type Transport } from "@modelcontextprotocol/sdk/shared/transport.js"
2-
import { type JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js"
31
import { Hono } from "hono"
42
import { HTTPException } from "hono/http-exception"
5-
6-
class OpenControlTransport implements Transport {
7-
constructor(private cb: (response: JSONRPCMessage) => void) {}
8-
async start(): Promise<void> {}
9-
async send(message: JSONRPCMessage): Promise<void> {
10-
this.cb(message)
11-
}
12-
async close(): Promise<void> {}
13-
onclose?: (() => void) | undefined
14-
onerror?: ((error: Error) => void) | undefined
15-
onmessage?: ((message: JSONRPCMessage) => void) | undefined
16-
}
3+
import { Tool } from "./tool.js"
4+
import { createMcp } from "./mcp.js"
175

186
export interface OpenControlOptions {
197
key?: string
208
}
219

22-
export function create(
23-
server: { connect: (transport: Transport) => Promise<void> },
24-
options?: OpenControlOptions,
25-
) {
10+
export function create(input: { tools: Tool[]; key?: string }) {
11+
const mcp = createMcp({ tools: input.tools })
12+
2613
return new Hono()
2714
.use((c, next) => {
28-
if (options?.key) {
15+
if (input?.key) {
2916
const authorization = c.req.header("Authorization")
30-
if (authorization !== `Bearer ${options?.key}`) {
17+
if (authorization !== `Bearer ${input?.key}`) {
3118
throw new HTTPException(401)
3219
}
3320
}
3421
return next()
3522
})
3623
.post("/mcp", async (c) => {
3724
const body = await c.req.json()
38-
console.log("<-", body)
39-
const response = await new Promise<any>(async (resolve) => {
40-
const transport = new OpenControlTransport(resolve)
41-
console.log("connecting to transport")
42-
await server.connect(transport)
43-
console.log("connected to transport")
44-
transport.onmessage?.(body)
45-
})
46-
console.log("->", JSON.stringify(response, null, 2))
47-
return c.json(response)
25+
const result = await mcp.process(body)
26+
return c.json(result)
4827
})
4928
}

packages/opencontrol/src/library/mysql.ts

Whitespace-only changes.

packages/opencontrol/src/library/postgres.ts

Whitespace-only changes.

packages/opencontrol/src/mcp.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import {
2+
CallToolRequestSchema,
3+
CallToolResult,
4+
InitializeRequestSchema,
5+
InitializeResult,
6+
JSONRPCRequest,
7+
JSONRPCResponse,
8+
ListToolsRequestSchema,
9+
ListToolsResult,
10+
} from "@modelcontextprotocol/sdk/types.js"
11+
import { z } from "zod"
12+
import { Tool } from "./tool.js"
13+
import { zodToJsonSchema } from "zod-to-json-schema"
14+
15+
const RequestSchema = z.union([
16+
InitializeRequestSchema,
17+
ListToolsRequestSchema,
18+
CallToolRequestSchema,
19+
])
20+
type RequestSchema = z.infer<typeof RequestSchema>
21+
22+
export function createMcp(input: { tools: Tool[] }) {
23+
return {
24+
async process(message: JSONRPCRequest) {
25+
const parsed = RequestSchema.parse(message)
26+
27+
const result = await (async () => {
28+
if (parsed.method === "initialize")
29+
return {
30+
protocolVersion: "2024-11-05",
31+
capabilities: {
32+
tools: {},
33+
},
34+
serverInfo: {
35+
name: "opencontrol",
36+
version: "0.0.1",
37+
},
38+
} satisfies InitializeResult
39+
40+
if (parsed.method === "tools/list") {
41+
return {
42+
tools: input.tools.map((tool) => ({
43+
name: tool.name,
44+
inputSchema: tool.args
45+
? (zodToJsonSchema(tool.args as any, "args").definitions![
46+
"args"
47+
] as any)
48+
: { type: "object" },
49+
description: tool.description,
50+
})),
51+
} satisfies ListToolsResult
52+
}
53+
54+
if (parsed.method === "tools/call") {
55+
const tool = input.tools.find(
56+
(tool) => tool.name === parsed.params.name,
57+
)
58+
if (!tool) throw new Error("tool not found")
59+
60+
let args = parsed.params.arguments
61+
if (tool.args) {
62+
const validated = await tool.args["~standard"].validate(args)
63+
if (validated.issues) {
64+
return {
65+
isError: true,
66+
content: [
67+
{
68+
type: "text",
69+
text: JSON.stringify(validated.issues),
70+
},
71+
],
72+
} satisfies CallToolResult
73+
}
74+
args = validated.value as any
75+
}
76+
77+
return tool
78+
.run(args)
79+
.catch(
80+
(error) =>
81+
({
82+
isError: true,
83+
content: [
84+
{
85+
type: "text",
86+
text: error.message,
87+
},
88+
],
89+
}) satisfies CallToolResult,
90+
)
91+
.then(
92+
(result) =>
93+
({
94+
content: [
95+
{
96+
type: "text",
97+
text: JSON.stringify(result, null, 2),
98+
},
99+
],
100+
}) satisfies CallToolResult,
101+
)
102+
}
103+
104+
throw new Error("not implemented")
105+
})()
106+
107+
return {
108+
jsonrpc: "2.0",
109+
id: message.id,
110+
result,
111+
} satisfies JSONRPCResponse
112+
},
113+
}
114+
}

packages/opencontrol/src/tool.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { StandardSchemaV1 } from "@standard-schema/spec"
2+
import { z } from "zod"
3+
4+
export interface Tool<
5+
Args extends undefined | StandardSchemaV1 = undefined | StandardSchemaV1,
6+
> {
7+
name: string
8+
description: string
9+
args?: Args
10+
run: Args extends StandardSchemaV1
11+
? (args: StandardSchemaV1.InferOutput<Args>) => Promise<any>
12+
: () => Promise<any>
13+
}
14+
15+
export function tool<Args extends undefined | StandardSchemaV1>(
16+
input: Tool<Args>,
17+
) {
18+
return input
19+
}
20+
21+
tool({
22+
name: "foo",
23+
description: "bar",
24+
args: z.object({
25+
foo: z.string(),
26+
}),
27+
async run(args) {},
28+
})

0 commit comments

Comments
 (0)