Docs
One endpoint for the tools your agent needs.
Laminaro publishes a single MCP endpoint. Your agent searches the granted catalog, reads one schema at a time, and invokes the capability. Everything else — policy, approvals, secrets, rate limits and audit — happens behind that call.
https://api.uselaminaro.com/mcp/<endpoint-slug>Quickstart
- 01
Create a workspace
Sign up, verify your address, and name the workspace your team will share. The console opens on the overview.
- 02
Connect a source
Connections hold an API description or a skill package. Paste an OpenAPI document, point at a URL, or import a skill zip. The catalog is scanned and versioned before anything is exposed.
- 03
Publish an endpoint
An endpoint is the single URL your agents call. Choose the environment and grant only the capabilities that endpoint may use. Grants are the boundary: an agent cannot reach a capability the endpoint does not hold.
- 04
Create an API key
Settings → API keys. Pick the connections the key may use, optionally narrow it to specific tools, and copy the key once. Store it in the client's secret manager, not in a prompt.
bashexport LAMINARO_API_KEY=sk_live_…
Connect a client
Any MCP client that speaks streamable HTTP works. Replace the slug and export the key before starting the client.
Claude Code
bashAdd the endpoint as a remote HTTP MCP server.
claude mcp add --transport http laminaro \
https://api.uselaminaro.com/mcp/<endpoint-slug> \
--header "Authorization: Bearer $LAMINARO_API_KEY"Claude Desktop and Cursor
jsonBoth read a JSON server map. Use the same URL and header.
{
"mcpServers": {
"laminaro": {
"url": "https://api.uselaminaro.com/mcp/<endpoint-slug>",
"headers": {
"Authorization": "Bearer sk_live_…"
}
}
}
}Paste the key directly; these clients do not expand environment variables. Keep the file out of version control.
Vercel AI SDK
typescriptConnect with the HTTP transport, then hand the tools to any model.
import { createMCPClient } from "@ai-sdk/mcp";
const mcp = await createMCPClient({
transport: {
type: "http",
url: "https://api.uselaminaro.com/mcp/<endpoint-slug>",
headers: { Authorization: `Bearer ${process.env.LAMINARO_API_KEY}` },
},
});
const tools = await mcp.tools();OpenAI Agents SDK
pythonUse the streamable HTTP server class with the same header.
import os
from agents import Agent
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(
name="Laminaro",
params={
"url": "https://api.uselaminaro.com/mcp/<endpoint-slug>",
"headers": {"Authorization": f"Bearer {os.environ['LAMINARO_API_KEY']}"},
},
) as server:
agent = Agent(name="Assistant", mcp_servers=[server])LangChain (JS)
typescriptMultiServerMCPClient speaks Streamable HTTP; getTools() feeds the standard agent.
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";
const client = new MultiServerMCPClient({
mcp: {
transport: "http",
url: "https://api.uselaminaro.com/mcp/<endpoint-slug>",
headers: { Authorization: `Bearer ${process.env.LAMINARO_API_KEY}` },
},
});
const tools = await client.getTools();
const agent = createAgent({ model: "openai:gpt-5.4", tools });Mastra
typescriptMCPClient takes the URL and a requestInit header; listTools() returns the tool set.
import { Agent } from "@mastra/core/agent";
import { MCPClient } from "@mastra/mcp";
const mcp = new MCPClient({
id: "laminaro",
servers: {
laminaro: {
url: new URL("https://api.uselaminaro.com/mcp/<endpoint-slug>"),
requestInit: {
headers: { Authorization: `Bearer ${process.env.LAMINARO_API_KEY}` },
},
},
},
});
const agent = new Agent({
name: "catalog",
instructions: "Search the catalog before invoking a capability.",
model: "openai/gpt-5",
tools: await mcp.listTools(),
});Call mcp.disconnect() when the process shuts down so the transport closes cleanly.
TanStack AI
typescriptcreateMCPClient runs on the server; pass it to chat() and the run closes it when it ends.
// Server route or serverless function, never browser code.
import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { createMCPClient } from "@tanstack/ai-mcp";
export async function POST(request: Request) {
const { messages } = await request.json();
const mcp = await createMCPClient({
transport: {
type: "http",
url: "https://api.uselaminaro.com/mcp/<endpoint-slug>",
headers: { Authorization: `Bearer ${process.env.LAMINARO_API_KEY}` },
},
});
const stream = chat({
adapter: openaiText("gpt-5.4"),
messages,
mcp: { clients: [mcp] },
});
return toServerSentEventsResponse(stream);
}chat() calls tools() before the first model call and closes the client on success, error and abort.
The catalog tools
The endpoint never dumps the catalog into the context window. It exposes three tools; the agent discovers one capability at a time.
capabilities.searchFinds capabilities by intent. Returns a short list with refs, never the whole catalog.
{ "query": "create a customer", "limit": 5 }capabilities.describeReturns the full input schema for one ref. Call it before invoking so the model sees only the schema it is about to use.
{ "ref": "stripe.create-customer" }capabilities.invokeExecutes the capability with the arguments its schema declared. Policy, approvals, secrets and audit all apply here.
{ "ref": "stripe.create-customer", "arguments": { "email": "[email protected]" } }Operations
Auth
Every request carries Authorization: Bearer <key>. Keys are scoped to connections and optionally to individual tools; a key can never widen the endpoint's grants. Console routes refuse API keys entirely.
Rate and usage
Each endpoint has its own requests-per-minute budget. Every tools/call counts as one request against the workspace allowance. Free is 1,000 requests and 10 sandbox minutes a month; paid plans continue into $0.30 per 1,000 requests above the included amount.
Environments
An endpoint targets production, staging or a custom environment. Grants, versions and secrets resolve per environment, so a staging key cannot call a production capability.
Audit
Every invocation records the caller, the capability version, the latency, the approval and the outcome. Export the trail as CSV from Audit.
Signed skill packages
Every published skill version carries an Ed25519 signature over its checksum, tree hash, canonical manifest digest and per-file digests. Fetch the public half at POST /rpc/skills/signingKey. A grant is refused if a file, manifest or signature no longer matches; unsigned legacy versions must be republished first.
Troubleshooting
401 Unauthorized
The key is missing, revoked or expired. Create a new key in Settings → API keys; the raw value is shown once.
403 Forbidden
The key is valid but not scoped to this endpoint, the browser Origin is not on the endpoint's allow-list, or your role lacks the permission.
404 Not found
The endpoint slug does not exist in an environment you belong to. Copy the URL from Endpoints rather than rebuilding it.
429 Too Many Requests
The endpoint's per-minute budget or the sandbox queue is full. Respect Retry-After instead of retrying immediately.
capabilities.invoke says the tool is unavailable
Search first, describe the exact ref, then invoke. The endpoint exposes three meta-tools, not the catalog itself.
Still stuck? Email [email protected] with the endpoint slug and the time of the call.