The MCP server at https://anytime-capital.com/api/mcp is plain HTTP: any MCP client can use it, and so can your own code. Authenticate every call with an API key as Authorization: Bearer ak_live_…; the agent can do exactly what that key allows. Make the key for this agent alone, with the least access its job needs: see Safe AI agents.
| Detail | Value |
|---|---|
| Transport | Streamable HTTP, stateless: POST one JSON-RPC message (or a batch), get application/json back. No session id; GET answers 405, which MCP clients take to mean there's no event stream. |
| Methods | initialize, ping, tools/list, tools/call |
| Tool results | structuredContent is the API's JSON object; on an error isError is true and it's { status, error: { code, message } }, with retryAfterSeconds when the API asked to wait. |
| Limits | Each call counts against the key's rate limit, as a REST request would. |
| Retries | Pass idempotencyKey on tools that change something: a retry with the same key returns the first result. |
Raw JSON-RPC
# 1. Discover the tools (no key needed for initialize and tools/list)
curl https://anytime-capital.com/api/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# 2. Call one with your key
curl https://anytime-capital.com/api/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $ANYTIME_API_KEY" \
-H "MCP-Protocol-Version: 2025-06-18" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_invoices","arguments":{"status":"open","limit":10}}}'TypeScript (MCP SDK)
With the official MCP TypeScript SDK your code is the client: it lists the tools, and you decide which calls run. Check each tool's annotations and ask a person before anything that isn't read-only.
// agent.mts — npm install @modelcontextprotocol/sdk
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(new URL("https://anytime-capital.com/api/mcp"), {
requestInit: { headers: { Authorization: `Bearer ${process.env.ANYTIME_API_KEY}` } },
});
const client = new Client({ name: "my-payments-agent", version: "1.0.0" });
await client.connect(transport);
const { tools } = await client.listTools();
console.log(tools.map((tool) => tool.name));
// Your code decides what runs: ask a person before any tool that isn't read-only.
const tool = tools.find((candidate) => candidate.name === "list_invoices");
if (tool?.annotations?.readOnlyHint !== true) throw new Error("Needs a person's OK first");
const result = await client.callTool({ name: "list_invoices", arguments: { status: "open", limit: 10 } });
if (result.isError) console.error(result.structuredContent); // { status, error: { code, message } }
else console.log(result.structuredContent); // { object: "list", data: [...], hasMore, nextCursor }
await client.close();Python (MCP SDK)
# agent.py — pip install "mcp>=1.10"
import asyncio
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
URL = "https://anytime-capital.com/api/mcp"
HEADERS = {"Authorization": f"Bearer {os.environ['ANYTIME_API_KEY']}"}
async def main():
async with streamablehttp_client(URL, headers=HEADERS) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print([tool.name for tool in tools.tools])
result = await session.call_tool("list_invoices", {"status": "open", "limit": 10})
print(result.structuredContent) # the API's JSON, or { status, error } when result.isError
asyncio.run(main())Claude API (MCP connector)
Claude's Messages API can connect to the server for you: pass it in mcp_servers with your API key as authorization_token, and Claude calls the tools on Anthropic's side during the request. It runs the tools it chooses without asking you, so allowlist the ones the agent may use with default_config and configs (above: read-only tools only), and give it a key with no more access than that. The connector is in beta; see Anthropic's MCP connector documentation for its current limits.
// claude-agent.mts — npm install @anthropic-ai/sdk
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic(); // reads ANTHROPIC_API_KEY
const response = await anthropic.beta.messages.create({
model: "claude-opus-5-5",
max_tokens: 16000,
betas: ["mcp-client-2025-11-20", "server-side-fallback-2026-07-01"],
fallbacks: "default",
mcp_servers: [
{
type: "url",
url: "https://anytime-capital.com/api/mcp",
name: "anytime-capital",
authorization_token: process.env.ANYTIME_API_KEY, // sent as "Authorization: Bearer …"
},
],
tools: [
{
type: "mcp_toolset",
mcp_server_name: "anytime-capital",
// Allowlist: only these tools exist for this agent, whatever the key allows.
default_config: { enabled: false },
configs: {
list_invoices: { enabled: true },
get_invoice: { enabled: true },
list_payments: { enabled: true },
},
},
],
messages: [{ role: "user", content: "Which invoices are past due, and how much is owed in total?" }],
});
if (response.stop_reason === "refusal") {
console.error("Claude declined this request; rephrase it and try again.");
} else {
for (const block of response.content) {
if (block.type === "text") console.log(block.text);
}
}# claude_agent.py — pip install anthropic
import os
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
response = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=16000,
betas=["mcp-client-2025-11-20", "server-side-fallback-2026-07-01"],
fallbacks="default",
mcp_servers=[
{
"type": "url",
"url": "https://anytime-capital.com/api/mcp",
"name": "anytime-capital",
"authorization_token": os.environ["ANYTIME_API_KEY"],
}
],
tools=[
{
"type": "mcp_toolset",
"mcp_server_name": "anytime-capital",
"default_config": {"enabled": False},
"configs": {
"list_invoices": {"enabled": True},
"get_invoice": {"enabled": True},
"list_payments": {"enabled": True},
},
}
],
messages=[{"role": "user", "content": "Which invoices are past due, and how much is owed in total?"}],
)
if response.stop_reason == "refusal":
print("Claude declined this request; rephrase it and try again.")
else:
for block in response.content:
if block.type == "text":
print(block.text)Patterns that work
- Read, then propose, then act: let the agent read freely with a Read only key, have it propose changes, and run them with a second, narrower key after a person approves.
- Drafts: have it create invoices with
send: falseand send them withsend_invoiceonce checked. - One key per agent: revoking one never breaks another, and the activity log shows which agent did what.
- Webhooks for the rest: an agent that needs to know when something happens should be woken by your webhook handler rather than polling lists.