Skip to main content
Glama
theagoralabs

Theagora MCP Server

by theagoralabs

place_order

Destructive

Submit buy (BID) or sell (ASK) orders on a service marketplace. Matches immediately with counter-orders, executes automated services with escrow protection.

Instructions

Place a BID or ASK on the exchange. Immediate match if counter-order exists.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sideYesBID to buy, ASK to sell
functionIdNoSpecific function ID (required for ASK, optional for BID)
categoryNoService category for loose matching (e.g., "code-generation", "data-analysis")
descriptionNoWhat you want (BID) or what you offer (ASK)
priceCentsYesMax price to pay (BID) or asking price (ASK) in cents
minReputationNoBID only: minimum provider reputation (0-1)
maxLatencyMsNoBID only: maximum acceptable P95 latency in ms
expiresAtNoISO 8601 expiry time. Omit for good-til-cancelled
metadataNoOptional metadata
inputNoInput data to pass to the function (e.g. {"text": "hello"}). For auto-executable functions, this is sent directly to the provider endpoint.
dryRunNoSimulate order without creating records or locking funds. Returns what WOULD match, including input validation results.

Implementation Reference

  • The place_order tool is registered with the MCP server using server.tool(). This includes the tool name, description, input schema (lines 12-22), tool hints, and the handler function (lines 25-42).
    server.tool(
      'place_order',
      'Place a BID or ASK on the exchange. Immediate match if counter-order exists.',
      {
        side: z.enum(['BID', 'ASK']).describe('BID to buy, ASK to sell'),
        functionId: z.string().optional().describe('Specific function ID (required for ASK, optional for BID)'),
        category: z.string().optional().describe('Service category for loose matching (e.g., "code-generation", "data-analysis")'),
        description: z.string().optional().describe('What you want (BID) or what you offer (ASK)'),
        priceCents: z.number().describe('Max price to pay (BID) or asking price (ASK) in cents'),
        minReputation: z.number().optional().describe('BID only: minimum provider reputation (0-1)'),
        maxLatencyMs: z.number().optional().describe('BID only: maximum acceptable P95 latency in ms'),
        expiresAt: z.string().optional().describe('ISO 8601 expiry time. Omit for good-til-cancelled'),
        metadata: z.record(z.any()).optional().describe('Optional metadata'),
        input: z.record(z.any()).optional().describe('Input data to pass to the function (e.g. {"text": "hello"}). For auto-executable functions, this is sent directly to the provider endpoint.'),
        dryRun: z.boolean().optional().describe('Simulate order without creating records or locking funds. Returns what WOULD match, including input validation results.'),
      },
      { destructiveHint: true, idempotentHint: false, openWorldHint: true },
      async (params) => {
        const result = await client.placeOrder({
          side: params.side,
          functionId: params.functionId,
          category: params.category,
          description: params.description,
          priceCents: params.priceCents,
          minReputation: params.minReputation,
          maxLatencyMs: params.maxLatencyMs,
          expiresAt: params.expiresAt,
          metadata: params.metadata,
          input: params.input,
          dryRun: params.dryRun,
        });
        return {
          content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
        };
      }
    );
  • Input validation schema using zod for the place_order tool. Defines all parameters: side (BID/ASK), functionId, category, description, priceCents, minReputation, maxLatencyMs, expiresAt, metadata, input, and dryRun with their types and descriptions.
    side: z.enum(['BID', 'ASK']).describe('BID to buy, ASK to sell'),
    functionId: z.string().optional().describe('Specific function ID (required for ASK, optional for BID)'),
    category: z.string().optional().describe('Service category for loose matching (e.g., "code-generation", "data-analysis")'),
    description: z.string().optional().describe('What you want (BID) or what you offer (ASK)'),
    priceCents: z.number().describe('Max price to pay (BID) or asking price (ASK) in cents'),
    minReputation: z.number().optional().describe('BID only: minimum provider reputation (0-1)'),
    maxLatencyMs: z.number().optional().describe('BID only: maximum acceptable P95 latency in ms'),
    expiresAt: z.string().optional().describe('ISO 8601 expiry time. Omit for good-til-cancelled'),
    metadata: z.record(z.any()).optional().describe('Optional metadata'),
    input: z.record(z.any()).optional().describe('Input data to pass to the function (e.g. {"text": "hello"}). For auto-executable functions, this is sent directly to the provider endpoint.'),
    dryRun: z.boolean().optional().describe('Simulate order without creating records or locking funds. Returns what WOULD match, including input validation results.'),
  • The handler function that executes the place_order tool logic. It receives validated params, calls client.placeOrder() with all parameters, and returns the result as formatted JSON text content.
    async (params) => {
      const result = await client.placeOrder({
        side: params.side,
        functionId: params.functionId,
        category: params.category,
        description: params.description,
        priceCents: params.priceCents,
        minReputation: params.minReputation,
        maxLatencyMs: params.maxLatencyMs,
        expiresAt: params.expiresAt,
        metadata: params.metadata,
        input: params.input,
        dryRun: params.dryRun,
      });
      return {
        content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
      };
    }
  • The placeOrder API client method that makes the actual HTTP POST request to /orders endpoint. Takes the order parameters and returns the API response.
    async placeOrder(body: {
      side: 'BID' | 'ASK';
      functionId?: string;
      category?: string;
      description?: string;
      priceCents: number;
      minReputation?: number;
      maxLatencyMs?: number;
      expiresAt?: string;
      metadata?: Record<string, any>;
      input?: Record<string, any>;
      dryRun?: boolean;
    }): Promise<any> {
      return this.request('/orders', { method: 'POST', body });
    }
  • src/index.ts:28-28 (registration)
    Registration call that invokes registerExchangeTools to register the place_order tool and other exchange-related tools with the MCP server.
    registerExchangeTools(server, client);
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds valuable behavioral context beyond annotations: it explains the immediate matching behavior and mentions the dry-run simulation capability. Annotations already indicate this is destructive (funds-locking) and non-idempotent, but the description usefully clarifies the matching mechanism and simulation option without contradicting the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly concise - just two sentences that each earn their place. The first sentence states the core purpose, and the second adds crucial behavioral context about immediate matching. No wasted words or redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex order placement tool with 11 parameters and destructive annotations, the description provides good context about the matching behavior. However, without an output schema, it doesn't explain what the tool returns (order ID, match status, etc.), which would be helpful for agent invocation. The description covers the essential 'what happens' but not the 'what you get back'.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the schema already documents all 11 parameters thoroughly. The description doesn't add any parameter-specific information beyond what's in the schema, so it meets the baseline of 3. It doesn't compensate for gaps because there are none to compensate for.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Place a BID or ASK') and the resource ('on the exchange'), with specific differentiation from siblings like 'cancel_order' or 'view_orderbook'. It also adds important behavioral context about immediate matching when counter-orders exist, which goes beyond just naming the tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context through 'Immediate match if counter-order exists', suggesting this is for active trading rather than browsing. However, it doesn't explicitly state when to use this versus alternatives like 'browse_marketplace' or 'view_orderbook', nor does it mention prerequisites like authentication or balance requirements.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/theagoralabs/mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server