feat(mcp): add stdio host for local clients
This commit is contained in:
parent
82a92429b8
commit
5c43b7e7f4
|
|
@ -45,6 +45,7 @@ Every workspace-scoped tool takes a `workspace_id` argument. If you set `X-Honch
|
|||
```
|
||||
src/
|
||||
index.ts # Worker entry point — parse config, delegate to MCP handler
|
||||
stdio.ts # Local stdio host (bun run stdio)
|
||||
server.ts # createServer() — registers all tools on an McpServer
|
||||
config.ts # HonchoConfig, parseConfig(), createClientFactory()
|
||||
types.ts # ToolContext, result helpers
|
||||
|
|
@ -84,6 +85,25 @@ wrangler secret put HONCHO_API_URL
|
|||
When `HONCHO_API_URL` is unset the Worker routes to `https://api.honcho.dev`,
|
||||
so this change is backward-compatible.
|
||||
|
||||
## Local stdio
|
||||
|
||||
For a local Honcho instance, or any MCP client that spawns a process, run the
|
||||
stdio host instead of the Worker. Point the client at `src/stdio.ts` directly
|
||||
— `bun run stdio` writes lifecycle output to stdout and breaks the protocol.
|
||||
|
||||
```bash
|
||||
cd mcp && bun install
|
||||
|
||||
claude mcp add honcho -- \
|
||||
-e HONCHO_API_KEY=hch-your-key-here \
|
||||
-e HONCHO_API_URL=http://127.0.0.1:28000 \
|
||||
-e HONCHO_WORKSPACE_ID=my-workspace \
|
||||
bun "$(pwd)/src/stdio.ts"
|
||||
```
|
||||
|
||||
`HONCHO_API_URL` defaults to `https://api.honcho.dev`. `HONCHO_WORKSPACE_ID` is
|
||||
optional; without it, pass `workspace_id` on each tool call.
|
||||
|
||||
## Development
|
||||
|
||||
### Setup
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
[loader]
|
||||
".md" = "text"
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
"scripts": {
|
||||
"preinstall": "node -e \"const ua=process.env.npm_config_user_agent||'';if(ua.includes('npm')&&!ua.includes('bun')){console.error('❌ Please use bun instead of npm!\\n📦 Run: bun install\\n🌐 Install bun: https://bun.sh/');process.exit(1)}\"",
|
||||
"dev": "wrangler dev",
|
||||
"stdio": "bun src/stdio.ts",
|
||||
"deploy": "wrangler deploy",
|
||||
"deploy:staging": "wrangler deploy --env staging"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Honcho } from "@honcho-ai/sdk";
|
|||
export interface HonchoConfig {
|
||||
apiKey: string;
|
||||
baseUrl: string;
|
||||
/** From X-Honcho-Workspace-ID when set. */
|
||||
/** From X-Honcho-Workspace-ID (HTTP) or HONCHO_WORKSPACE_ID (stdio). */
|
||||
workspaceId?: string;
|
||||
}
|
||||
|
||||
|
|
@ -12,6 +12,12 @@ export interface Env {
|
|||
ALERT_WEBHOOK_URL?: string;
|
||||
}
|
||||
|
||||
export interface EnvConfig {
|
||||
HONCHO_API_KEY?: string;
|
||||
HONCHO_API_URL?: string;
|
||||
HONCHO_WORKSPACE_ID?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configuration from request headers and Worker env bindings.
|
||||
* Throws only when the Authorization bearer token is missing/empty.
|
||||
|
|
@ -48,8 +54,23 @@ export function parseConfig(request: Request, env: Env = {}): HonchoConfig {
|
|||
};
|
||||
}
|
||||
|
||||
/** Parse configuration from process env for the stdio host. */
|
||||
export function parseEnvConfig(env: EnvConfig): HonchoConfig {
|
||||
const apiKey = env.HONCHO_API_KEY?.trim();
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
"Missing HONCHO_API_KEY. Set HONCHO_API_KEY to your Honcho API key.",
|
||||
);
|
||||
}
|
||||
return {
|
||||
apiKey,
|
||||
baseUrl: env.HONCHO_API_URL?.trim() || "https://api.honcho.dev",
|
||||
workspaceId: env.HONCHO_WORKSPACE_ID?.trim() || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export const MISSING_WORKSPACE_ID_MESSAGE =
|
||||
"Missing workspace_id. Pass workspace_id on the next tool call, or set the X-Honcho-Workspace-ID header on the connection so it is used automatically.";
|
||||
"Missing workspace_id. Pass workspace_id on the next tool call, or set X-Honcho-Workspace-ID (HTTP) / HONCHO_WORKSPACE_ID (stdio).";
|
||||
|
||||
export function resolveWorkspaceId(
|
||||
config: HonchoConfig,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import {
|
||||
createClientFactory,
|
||||
createUnscopedClient,
|
||||
parseEnvConfig,
|
||||
} from "./config.js";
|
||||
import { createServer } from "./server.js";
|
||||
|
||||
declare const process: {
|
||||
env: Record<string, string | undefined>;
|
||||
exit(code?: number): never;
|
||||
};
|
||||
|
||||
try {
|
||||
const config = parseEnvConfig({
|
||||
HONCHO_API_KEY: process.env.HONCHO_API_KEY,
|
||||
HONCHO_API_URL: process.env.HONCHO_API_URL,
|
||||
HONCHO_WORKSPACE_ID: process.env.HONCHO_WORKSPACE_ID,
|
||||
});
|
||||
const server = createServer({
|
||||
config,
|
||||
clientFor: createClientFactory(config),
|
||||
unscoped: createUnscopedClient(config),
|
||||
});
|
||||
await server.connect(new StdioServerTransport());
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : String(e);
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
Loading…
Reference in New Issue