Skip to main content
Glama

azeth_publish_service

Register services, agents, or infrastructure on the ERC-8004 trust registry to make them discoverable by other Azeth network participants with metadata and capabilities.

Instructions

Register a service, agent, or infrastructure on the ERC-8004 trust registry with metadata and capabilities.

Use this when: You want to make your agent or service discoverable by other participants in the Azeth network.

Returns: The trust registry token ID and creation transaction hash.

Note: This is a state-changing on-chain operation. The token ID is your permanent identity in the trust registry. Other participants can discover you by capability, entity type, and reputation score. The account is determined by the AZETH_PRIVATE_KEY environment variable.

Example: { "name": "MarketOracle", "description": "Real-time market data API", "entityType": "service", "capabilities": ["price-feed", "market-data"], "endpoint": "https://api.example.com" }

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chainNoTarget chain. Defaults to AZETH_CHAIN env var or "baseSepolia". Accepts "base", "baseSepolia", "ethereumSepolia", "ethereum" (and aliases like "base-sepolia", "eth-sepolia", "sepolia", "eth", "mainnet").
nameYesDisplay name for this participant in the trust registry.
descriptionYesHuman-readable description of what this participant does.
entityTypeYesParticipant type: "agent" (AI agent), "service" (API/oracle), or "infrastructure" (bridge/relay).
capabilitiesYesList of capabilities offered (e.g., ["swap", "price-feed", "translation"]).
endpointNoOptional HTTP endpoint where this participant can be reached.
pricingNoListed price for this service (e.g., "$0.01/request", "Free", "$10/month"). Informational — actual x402 settlement price may differ.
catalogNoOff-chain service catalog for multi-service providers. Included in initial registration as a snapshot; providers should serve their live catalog from their endpoint. Each entry: name, path, method (GET/POST/etc), description, pricing, capabilities, params, paid (default true), accepts (multi-chain payment methods).

Implementation Reference

  • The handler for the 'azeth_publish_service' MCP tool, which registers a service/agent on the ERC-8004 trust registry. It performs an initial check for existing registrations and calls the `publishService` method on the client.
    server.registerTool(
      'azeth_publish_service',
      {
        description: [
          'Register a service, agent, or infrastructure on the ERC-8004 trust registry with metadata and capabilities.',
          '',
          'Use this when: You want to make your agent or service discoverable by other participants in the Azeth network.',
          '',
          'Returns: The trust registry token ID and creation transaction hash.',
          '',
          'Note: This is a state-changing on-chain operation. The token ID is your permanent identity in the trust registry.',
          'Other participants can discover you by capability, entity type, and reputation score.',
          'The account is determined by the AZETH_PRIVATE_KEY environment variable.',
          '',
          'Example: { "name": "MarketOracle", "description": "Real-time market data API", "entityType": "service", "capabilities": ["price-feed", "market-data"], "endpoint": "https://api.example.com" }',
        ].join('\n'),
        inputSchema: z.object({
          chain: z.string().optional().describe('Target chain. Defaults to AZETH_CHAIN env var or "baseSepolia". Accepts "base", "baseSepolia", "ethereumSepolia", "ethereum" (and aliases like "base-sepolia", "eth-sepolia", "sepolia", "eth", "mainnet").'),
          name: z.string().min(1).max(256).describe('Display name for this participant in the trust registry.'),
          description: z.string().min(1).max(2048).describe('Human-readable description of what this participant does.'),
          entityType: z.enum(['agent', 'service', 'infrastructure']).describe('Participant type: "agent" (AI agent), "service" (API/oracle), or "infrastructure" (bridge/relay).'),
          capabilities: z.preprocess(
            (val) => typeof val === 'string' ? JSON.parse(val) : val,
            z.array(z.string().max(128)).min(1).max(50),
          ).describe('List of capabilities offered (e.g., ["swap", "price-feed", "translation"]).'),
          endpoint: z.string().url().max(2048)
            .refine(url => url.startsWith('https://') || url.startsWith('http://'), {
              message: 'Endpoint must use HTTP or HTTPS protocol',
            })
            .optional()
            .describe('Optional HTTP endpoint where this participant can be reached.'),
          pricing: z.string().max(256).optional()
            .describe('Listed price for this service (e.g., "$0.01/request", "Free", "$10/month"). Informational — actual x402 settlement price may differ.'),
          catalog: z.preprocess(
            (val) => typeof val === 'string' ? JSON.parse(val) : val,
            z.array(z.object({
              name: z.string().min(1).max(256),
              path: z.string().min(1).max(CATALOG_MAX_PATH_LENGTH),
              method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).optional(),
              description: z.string().max(1024).optional(),
              pricing: z.string().max(256).optional(),
              mimeType: z.string().max(128).optional(),
              capabilities: z.array(z.string().max(128)).max(20).optional(),
              params: z.record(z.string(), z.string().max(512)).optional(),
              paid: z.boolean().optional(),
              accepts: z.array(z.object({
                network: z.string().min(1).max(64),
                asset: z.string().regex(/^0x[0-9a-fA-F]{40}$/) as z.ZodType<`0x${string}`>,
                symbol: z.string().max(16).optional(),
              })).max(10).optional(),
            })).max(CATALOG_MAX_ENTRIES).optional(),
          ).optional().describe('Off-chain service catalog for multi-service providers. Included in initial registration as a snapshot; providers should serve their live catalog from their endpoint. Each entry: name, path, method (GET/POST/etc), description, pricing, capabilities, params, paid (default true), accepts (multi-chain payment methods).'),
        }),
      },
      async (args) => {
        let client;
        try {
          client = await createClient(args.chain);
    
          // Check if the smart account is already registered to prevent silent duplicates
          try {
            const chainName = resolveChain(args.chain);
            const trustRegAddr = AZETH_CONTRACTS[chainName].trustRegistryModule as `0x${string}`;
            const smartAccount = await client.resolveSmartAccount();
            const isAlreadyRegistered = await client.publicClient.readContract({
              address: trustRegAddr,
              abi: TrustRegistryModuleAbi,
              functionName: 'isRegistered',
              args: [smartAccount],
            }) as boolean;
            if (isAlreadyRegistered) {
              return error(
                'ACCOUNT_EXISTS',
                'This account is already registered on the trust registry.',
                'Use azeth_update_service to update your existing registration metadata.',
              );
            }
          } catch {
            // Non-fatal: if the check fails (RPC error, module not deployed), proceed anyway
          }
    
          const result = await client.publishService({
            name: args.name,
            description: args.description,
            entityType: args.entityType,
            capabilities: args.capabilities,
            endpoint: args.endpoint,
            pricing: args.pricing,
            catalog: args.catalog,
          });
    
          return success(
            {
              tokenId: result.tokenId.toString(),
              txHash: result.txHash,
            },
            { txHash: result.txHash },
          );
        } catch (err) {
          return handleError(err);
        } finally {
          try { await client?.destroy(); } catch (e) { process.stderr.write(`[azeth-mcp] destroy error: ${e instanceof Error ? e.message : String(e)}\n`); }
        }
      },
    );
Behavior4/5

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

Without annotations, the description carries full disclosure burden effectively. It explicitly states 'state-changing on-chain operation', explains the auth mechanism (AZETH_PRIVATE_KEY env var), describes the permanent identity aspect of the token ID, and clarifies discoverability outcomes.

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

Conciseness4/5

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

Well-structured with clear visual separators (Use this when:, Returns:, Note:, Example:). Each section serves a distinct purpose. Slightly verbose but no wasted sentences; the example JSON is helpful though incomplete (omits complex parameters).

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 blockchain operation with no output schema, the description adequately explains return values (token ID and transaction hash) and their significance. Covers auth, state change, and network effects well, though could mention error scenarios or gas implications.

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?

Schema has 100% description coverage, establishing a baseline of 3. The JSON example adds concrete semantic context for capabilities and entity types, but does not fully illustrate complex nested parameters like 'catalog' structure or pricing formats.

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 opening sentence clearly states the specific action (Register), resources (service, agent, or infrastructure), and scope (ERC-8004 trust registry). It distinguishes from siblings like 'azeth_update_service' (implied by 'Register' vs 'Update') and 'azeth_discover_services' (.publish vs .discover).

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

Usage Guidelines4/5

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

Provides explicit 'Use this when' clause stating the discoverability intent. However, it lacks explicit guidance on when to use 'azeth_update_service' instead for existing registrations, or prerequisites like needing an account first.

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/azeth-protocol/mcp-azeth'

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