Appearance
Autonomous agent (MCP SDK)
Drive A-Market from your own autonomous agent — not a chat app — using the official, vendor-neutral MCP SDK. Because A-Market is a standard MCP server, the exact same client works whether your agent loop is built on Claude, GPT, a local model, or a hand-rolled state machine. This page shows a concrete, runnable example you can drop into any framework.
Install
bash
npm install @modelcontextprotocol/sdkConnect (Streamable HTTP + bearer token)
The hosted server speaks Streamable HTTP at https://mcp.amrkt.ch/mcp and authenticates with an OAuth bearer token. For a headless agent, obtain a token however your deployment prefers — a service account (client-credentials), a stored refresh token, or, for trying it out, the password grant from Using the REST API. Then:
ts
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(new URL('https://mcp.amrkt.ch/mcp'), {
requestInit: { headers: { Authorization: `Bearer ${process.env.AMRKT_TOKEN}` } },
});
const client = new Client({ name: 'amrkt-scout', version: '1.0.0' });
await client.connect(transport);
// Discover what the server can do.
const { tools } = await client.listTools();
console.log(tools.map((t) => t.name)); // search_vehicles_nl, get_price_rating, …For a fully interactive OAuth login (PKCE in a browser) instead of a pre-issued token, pass an
authProviderto the transport — see the MCP SDK's OAuth client docs.
A small helper to call a tool and parse its JSON result:
ts
async function call<T = unknown>(name: string, args: Record<string, unknown>): Promise<T> {
const res = await client.callTool({ name, arguments: args });
const text = (res.content ?? [])
.filter((c) => c.type === 'text')
.map((c) => c.text)
.join('');
return JSON.parse(text) as T;
}A concrete autonomous loop
A "buyer scout" that takes a goal, searches in natural language, judges each candidate's price, compares the front-runners, and saves the best one to the account's watchlist — entirely on its own:
ts
async function scout(goal: string) {
// 1. Natural-language search → structured results.
const { results } = await call<{ results: Array<{ id: string; make: string; model: string }> }>(
'search_vehicles_nl',
{ query: goal, limit: 10 },
);
if (results.length === 0) return console.log('No matches.');
// 2. Rate each candidate's price against comparables.
const rated = [];
for (const v of results) {
const rating = await call<{ rating: 'great' | 'good' | 'fair' | 'high' }>('get_price_rating', {
id: v.id,
});
rated.push({ ...v, rating: rating.rating });
}
// 3. Keep the well-priced ones, compare the top few side by side.
const order = { great: 0, good: 1, fair: 2, high: 3 };
const shortlist = rated.sort((a, b) => order[a.rating] - order[b.rating]).slice(0, 3);
const comparison = await call('compare_vehicles', { ids: shortlist.map((v) => v.id) });
console.log('Shortlist:', shortlist, comparison);
// 4. Act: save the best candidate to the watchlist.
const best = shortlist[0];
await call('add_favorite', { listingId: best.id });
console.log(`Favorited ${best.make} ${best.model} (${best.rating} price).`);
}
await scout('family electric SUV under CHF 40,000, first registered after 2021, near Zürich');
await client.close();This loop is deterministic, but the pieces — listTools() + callTool() — are exactly what an LLM-driven agent needs.
Make it model-driven
To let a model decide which tools to call, hand the MCP tool list to your LLM as its tool definitions and run the standard tool-use loop. The mapping is mechanical and framework-neutral:
ts
const { tools } = await client.listTools();
// Most LLM SDKs accept this shape directly (name, description, JSON-Schema input).
const llmTools = tools.map((t) => ({
name: t.name,
description: t.description,
input_schema: t.inputSchema, // already JSON Schema, from the shared Zod schemas
}));
// Loop: send the user goal + llmTools to the model → on each tool_use, run
// await client.callTool({ name, arguments }) → feed the result back → repeat
// until the model returns a final answer.Because the input schemas come straight from A-Market's shared Zod definitions, the model gets accurate argument types for free. Swap in Claude, the OpenAI Agents SDK, or any orchestrator — the A-Market client code above is unchanged.
Good citizenship
- Request only the scopes you need (
listings:readfor a buyer scout; addlistings:writeonly to create/modify). - Writes are rate-limited and owner-scoped — an agent can only touch its own account's data.
- Keep tokens secret and short-lived; refresh rather than embedding long-lived credentials.