mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
update api
This commit is contained in:
parent
f11a8bdf71
commit
f964c4f15c
5 changed files with 126 additions and 8 deletions
|
|
@ -509,7 +509,18 @@ export namespace ACP {
|
|||
|
||||
await Promise.all(
|
||||
Object.entries(mcpServers).map(async ([key, mcp]) => {
|
||||
await MCP.add(key, mcp)
|
||||
await this.sdk.mcp
|
||||
.add({
|
||||
throwOnError: true,
|
||||
query: { directory },
|
||||
body: {
|
||||
name: key,
|
||||
config: mcp,
|
||||
},
|
||||
})
|
||||
.catch((error) => {
|
||||
log.error("failed to add mcp server", { name: key, error })
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -92,13 +92,28 @@ export namespace MCP {
|
|||
export async function add(name: string, mcp: Config.Mcp) {
|
||||
const s = await state()
|
||||
const result = await create(name, mcp)
|
||||
if (!result) return
|
||||
if (!result) {
|
||||
const status = {
|
||||
status: "failed" as const,
|
||||
error: "unknown error",
|
||||
}
|
||||
s.status[name] = status
|
||||
return {
|
||||
status,
|
||||
}
|
||||
}
|
||||
if (!result.mcpClient) {
|
||||
s.status[name] = result.status
|
||||
return
|
||||
return {
|
||||
status: s.status,
|
||||
}
|
||||
}
|
||||
s.clients[name] = result.mcpClient
|
||||
s.status[name] = result.status
|
||||
|
||||
return {
|
||||
status: s.status,
|
||||
}
|
||||
}
|
||||
|
||||
async function create(key: string, mcp: Config.Mcp) {
|
||||
|
|
@ -207,8 +222,12 @@ export namespace MCP {
|
|||
}
|
||||
}
|
||||
|
||||
const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch(() => {})
|
||||
const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch((err) => {
|
||||
log.error("create() failed to get tools from client", { key, error: err })
|
||||
return undefined
|
||||
})
|
||||
if (!result) {
|
||||
log.info("create() tools() returned nothing, closing client", { key })
|
||||
await mcpClient.close().catch((error) => {
|
||||
log.error("Failed to close MCP client", {
|
||||
error,
|
||||
|
|
@ -227,6 +246,7 @@ export namespace MCP {
|
|||
}
|
||||
}
|
||||
|
||||
log.info("create() successfully created client", { key, toolCount: Object.keys(result).length })
|
||||
return {
|
||||
mcpClient,
|
||||
status,
|
||||
|
|
@ -238,13 +258,18 @@ export namespace MCP {
|
|||
}
|
||||
|
||||
export async function clients() {
|
||||
return state().then((state) => state.clients)
|
||||
const s = await state()
|
||||
log.info("clients() called", { clientCount: Object.keys(s.clients).length })
|
||||
return s.clients
|
||||
}
|
||||
|
||||
export async function tools() {
|
||||
const result: Record<string, Tool> = {}
|
||||
const s = await state()
|
||||
for (const [clientName, client] of Object.entries(await clients())) {
|
||||
log.info("tools() called", { clientCount: Object.keys(s.clients).length })
|
||||
const clientsSnapshot = await clients()
|
||||
for (const [clientName, client] of Object.entries(clientsSnapshot)) {
|
||||
log.info("tools() fetching tools for client", { clientName })
|
||||
const tools = await client.tools().catch((e) => {
|
||||
log.error("failed to get tools", { clientName, error: e.message })
|
||||
const failedStatus = {
|
||||
|
|
@ -255,14 +280,17 @@ export namespace MCP {
|
|||
delete s.clients[clientName]
|
||||
})
|
||||
if (!tools) {
|
||||
log.info("tools() no tools returned for client", { clientName })
|
||||
continue
|
||||
}
|
||||
log.info("tools() got tools for client", { clientName, toolCount: Object.keys(tools).length })
|
||||
for (const [toolName, tool] of Object.entries(tools)) {
|
||||
const sanitizedClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "_")
|
||||
const sanitizedToolName = toolName.replace(/[^a-zA-Z0-9_-]/g, "_")
|
||||
result[sanitizedClientName + "_" + sanitizedToolName] = tool
|
||||
}
|
||||
}
|
||||
log.info("tools() final result", { toolCount: Object.keys(result).length })
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1359,6 +1359,36 @@ export namespace Server {
|
|||
return c.json(await MCP.status())
|
||||
},
|
||||
)
|
||||
.post(
|
||||
"/mcp",
|
||||
describeRoute({
|
||||
description: "Add MCP server dynamically",
|
||||
operationId: "mcp.add",
|
||||
responses: {
|
||||
200: {
|
||||
description: "MCP server added successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.record(z.string(), MCP.Status)),
|
||||
},
|
||||
},
|
||||
},
|
||||
...errors(400),
|
||||
},
|
||||
}),
|
||||
validator(
|
||||
"json",
|
||||
z.object({
|
||||
name: z.string(),
|
||||
config: Config.Mcp,
|
||||
}),
|
||||
),
|
||||
async (c) => {
|
||||
const { name, config } = c.req.valid("json")
|
||||
const result = await MCP.add(name, config)
|
||||
return c.json(result.status)
|
||||
},
|
||||
)
|
||||
.get(
|
||||
"/lsp",
|
||||
describeRoute({
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@ import type {
|
|||
AppAgentsResponses,
|
||||
McpStatusData,
|
||||
McpStatusResponses,
|
||||
McpAddData,
|
||||
McpAddResponses,
|
||||
McpAddErrors,
|
||||
LspStatusData,
|
||||
LspStatusResponses,
|
||||
FormatterStatusData,
|
||||
|
|
@ -764,6 +767,20 @@ class Mcp extends _HeyApiClient {
|
|||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Add MCP server dynamically
|
||||
*/
|
||||
public add<ThrowOnError extends boolean = false>(options?: Options<McpAddData, ThrowOnError>) {
|
||||
return (options?.client ?? this._client).post<McpAddResponses, McpAddErrors, ThrowOnError>({
|
||||
url: "/mcp",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class Lsp extends _HeyApiClient {
|
||||
|
|
|
|||
|
|
@ -1979,9 +1979,9 @@ export type SessionMessagesData = {
|
|||
*/
|
||||
id: string
|
||||
}
|
||||
query?: {
|
||||
query: {
|
||||
directory?: string
|
||||
limit?: number
|
||||
limit: number
|
||||
}
|
||||
url: "/session/{id}/message"
|
||||
}
|
||||
|
|
@ -2552,6 +2552,38 @@ export type McpStatusResponses = {
|
|||
|
||||
export type McpStatusResponse = McpStatusResponses[keyof McpStatusResponses]
|
||||
|
||||
export type McpAddData = {
|
||||
body?: {
|
||||
name: string
|
||||
config: McpLocalConfig | McpRemoteConfig
|
||||
}
|
||||
path?: never
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/mcp"
|
||||
}
|
||||
|
||||
export type McpAddErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: BadRequestError
|
||||
}
|
||||
|
||||
export type McpAddError = McpAddErrors[keyof McpAddErrors]
|
||||
|
||||
export type McpAddResponses = {
|
||||
/**
|
||||
* MCP server added successfully
|
||||
*/
|
||||
200: {
|
||||
[key: string]: McpStatus
|
||||
}
|
||||
}
|
||||
|
||||
export type McpAddResponse = McpAddResponses[keyof McpAddResponses]
|
||||
|
||||
export type LspStatusData = {
|
||||
body?: never
|
||||
path?: never
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue