Skip to content
Merged
58 changes: 58 additions & 0 deletions src/commands/connect/add-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export async function addServer(
metadata?: string
headers?: string
namespace?: string
force?: boolean
},
): Promise<void> {
try {
Expand All @@ -24,17 +25,74 @@ export async function addServer(

const normalizedUrl = normalizeMcpUrl(mcpUrl)
const session = await ConnectSession.create(options.namespace)

// Check for existing connections with the same URL
if (!options.force) {
const { connections: existing } =
await session.listConnectionsByUrl(normalizedUrl)
if (existing.length > 0) {
const match = existing[0]
const status = match.status?.state ?? "unknown"
console.error(
chalk.yellow(
`Connection already exists for this URL: ${match.name} (${match.connectionId}, status: ${status})`,
),
)
if (status === "auth_required") {
const authUrl = (match.status as { authorizationUrl?: string })
?.authorizationUrl
if (authUrl) {
console.error(
chalk.yellow(`Authorization required. Run: open "${authUrl}"`),
)
}
} else if (status === "connected") {
console.error(
chalk.yellow(
`Use "smithery connect tools ${match.connectionId}" to interact with it.`,
),
)
}
console.error(
chalk.dim(`Use --force to create a new connection anyway.`),
)
const output = formatConnectionOutput(match)
outputJson(output)
return
}
}

const connection = await session.createConnection(normalizedUrl, {
name: options.name,
metadata: parsedMetadata,
headers: parsedHeaders,
})

if (connection.status?.state === "auth_required") {
const authUrl = (connection.status as { authorizationUrl?: string })
?.authorizationUrl
if (authUrl) {
console.error(
chalk.yellow(`Authorization required. Run: open "${authUrl}"`),
)
}
}

const output = formatConnectionOutput(connection)
outputJson(output)
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
console.error(chalk.red(`Failed to add connection: ${errorMessage}`))
if (
errorMessage.includes("Missing required permission") ||
errorMessage.includes("403")
) {
console.error(
chalk.yellow(
`\nYour authentication token may be expired or missing required permissions. Run "smithery login" to re-authenticate.`,
),
)
}
process.exit(1)
}
}
11 changes: 11 additions & 0 deletions src/commands/connect/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ export class ConnectSession {
return new ConnectSession(client, ns)
}

async listConnectionsByUrl(
mcpUrl: string,
): Promise<{ connections: Connection[] }> {
const data =
await this.smitheryClient.experimental.connect.connections.list(
this.namespace,
{ mcpUrl },
)
return { connections: data.connections }
}

async listConnections(options?: {
limit?: number
cursor?: string
Expand Down
1 change: 1 addition & 0 deletions src/commands/connect/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export async function listServers(options: {
servers: connections.map((conn) => ({
id: conn.connectionId,
name: conn.name,
mcpUrl: conn.mcpUrl,
status: conn.status?.state ?? "unknown",
})),
help: "smithery connect tools <server> - List tools for a specific server",
Expand Down
Loading