Gives the caller's org one more external MCP server, so its tools join the…
Gives the caller's org one more external MCP server, so its tools join the org's tool plane and the fleet's MCP door.
POST /v1/tools/mcp/servers
| Address | https://api.hanzo.ai/v1/tools/mcp/servers |
| Method | POST |
| Operation | post_tools_mcp_servers |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Gives the caller's org one more external MCP server, so its tools
join the org's tool plane and the fleet's MCP door. It is the ONE way an org
gains a server, whether it typed the URL in or enabled a catalog listing: both
write the SAME record, and source says which it was. A second registration
path would be a second place for a server to exist, and then a second place to
forget to check the credential.
The credential VALUE is sealed in KMS under a per-org ref; the row keeps only the URL, the header name to inject it into, and a has-secret flag — so a secret with no KMS configured is refused 503 rather than stored in the clear. The URL is SSRF-validated here and re-checked by the dialer at connect time, which is the DNS-rebinding defense.
Enabling a listing the org already enabled REVISES that server rather than adding a near-duplicate beside it, so a retried enable is the same one server. Answers 201 with the stored record.
Request
5 fields, body application/json (required).
| Field | In | Type | Required | Description |
|---|---|---|---|---|
authHeader | body | string | — | AuthHeader is the request header the credential is injected into, e.g. |
listing | body | string | — | Listing enables a CATALOG entry instead — the id from GET /v1/tools/catalog. |
name | body | string | — | Name labels the server for the org. |
secret | body | string | — | Secret is the credential VALUE. |
url | body | string | — | URL is the server's JSON-RPC endpoint. It must be an http(s) URL naming a PUBLIC host: loopback, link-local, private and cloud-metadata addresses are refused… |
Response
| Status | Body | Meaning |
|---|---|---|
201 | MCPServer | created |
201 body — 9 fields.
| Field | In | Type | Always | Description |
|---|---|---|---|---|
authHeader | body | string | — | AuthHeader is the request header the KMS-held credential is injected into, e.g. |
createdAt | body | integer | — | CreatedAt is when the server was registered, Unix seconds. |
hasSecret | body | boolean | — | HasSecret is whether a credential is sealed in KMS for this server. |
id | body | string | — | ID is the server's id within the org. |
listing | body | string | — | Listing is the catalog entry this server was enabled from, when it was. |
name | body | string | — | Name is the org's label for the server. |
org | body | string | — | Org is the org that registered the server — the validated caller's. |
source | body | string | — | Source is where the registration came from: "catalog" when it was enabled off the shelf, "org" when the org registered the URL itself. |
url | body | string | — | URL is the server's JSON-RPC endpoint. |
Failure carries the platform error shape — see Errors.
Examples
hanzo has no subcommand for this operation — the CLI serves only what cloud's live route table confirms. Use HTTP or an SDK.
import { Configuration, ToolsApi } from 'hanzoai';
const api = new ToolsApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postToolsMcpServers({ authHeader: "<authHeader>", listing: "<listing>" });from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import ToolsApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = ToolsApi(client).post_tools_mcp_servers(auth_header="<authHeader>", listing="<listing>")cfg := cloud.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := cloud.NewAPIClient(cfg)
resp, _, err := client.ToolsAPI.PostToolsMcpServers(context.Background()).Execute()
if err != nil {
return err
}use hanzo_cloud::apis::{configuration::Configuration, tools_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = tools_api::post_tools_mcp_servers(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.ToolsApi;
ApiClient client = new ApiClient();
client.setRequestInterceptor(b -> b.header("Authorization", "Bearer " + System.getenv("HANZO_API_KEY")));
var result = new ToolsApi(client).postToolsMcpServers();The method above is the one at the current release of the document. [email protected] (npm) and [email protected] (PyPI) were generated from an earlier release, where this operation carried a different id, so it spells the method differently — regenerating the clients is what makes the two agree. SDKs →
curl -X POST https://api.hanzo.ai/v1/tools/mcp/servers \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"authHeader": "<authHeader>",
"listing": "<listing>"
}'The door reaches tools through the tools tool, which names its 19 operations with its own verbs — this one among them, under a name only the door declares. describe explains any of them:
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe",
"arguments": {
"op": "list_mcp_servers"
}
}
}'How is this guide?