Skip to main content
Glama
ejentum

ejentum-mcp

Official

harness_memory

Sharpens observed patterns in conversation state, user behavior, or emotional shifts by returning a perception scaffold to verify if a felt signal is real.

Instructions

Call when sharpening a perception or observation you ALREADY formed about conversation state, user behavior, drift, emotional shifts, or cross-turn patterns. Trigger queries: "what did you notice about X", "the user keeps doing Y", "I sense something has changed", "is the user X-ing", "what does this pattern suggest", "what shifted across our turns", "am I missing something here", "why did the conversation move from X to Y", or any moment when you need to verify whether a felt signal is real or projection. The tool returns a perception scaffold (perception failure, detection procedure, suppression vectors) that SHARPENS an observation you already have. It is NOT a substitute for observing first; if you have not noticed anything yet, do not call. DO NOT call for: fact extraction, summarization, list-making, factual lookups, or write-heavy memory tasks (storing or retrieving structured data). Memory harness is filter/perception oriented; calling on write-heavy tasks produces scaffold paralysis. When in doubt: observe FIRST, then call with your raw observation as the framing. Pass a specific 1-2 sentence "I noticed X, this might mean Y, sharpen Z" framing. Absorb the scaffold internally; do NOT echo bracket labels.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes1-2 sentence framing of the task you need the harness for. Be specific about WHAT you are trying to do, not what tool you want. Good: 'diagnose why a microservice returns 503s under load'. Bad: 'help me think'.

Implementation Reference

  • src/index.ts:33-38 (registration)
    Registration of the 'harness_memory' tool in the HARNESSES array with mode 'memory' and description.
    {
      name: "harness_memory",
      mode: "memory",
      description:
        "Call when sharpening a perception or observation you ALREADY formed about conversation state, user behavior, drift, emotional shifts, or cross-turn patterns. Trigger queries: \"what did you notice about X\", \"the user keeps doing Y\", \"I sense something has changed\", \"is the user X-ing\", \"what does this pattern suggest\", \"what shifted across our turns\", \"am I missing something here\", \"why did the conversation move from X to Y\", or any moment when you need to verify whether a felt signal is real or projection. The tool returns a perception scaffold (perception failure, detection procedure, suppression vectors) that SHARPENS an observation you already have. It is NOT a substitute for observing first; if you have not noticed anything yet, do not call. DO NOT call for: fact extraction, summarization, list-making, factual lookups, or write-heavy memory tasks (storing or retrieving structured data). Memory harness is filter/perception oriented; calling on write-heavy tasks produces scaffold paralysis. When in doubt: observe FIRST, then call with your raw observation as the framing. Pass a specific 1-2 sentence \"I noticed X, this might mean Y, sharpen Z\" framing. Absorb the scaffold internally; do NOT echo bracket labels.",
    },
  • The callHarness function is the handler that executes the tool logic by sending the query and mode (including 'memory') to the Ejentum API and returning the response.
    export async function callHarness(
      query: string,
      mode: HarnessMode,
    ): Promise<string> {
      const apiKey = process.env.EJENTUM_API_KEY;
      if (!apiKey || apiKey.trim().length === 0) {
        throw new Error(
          "EJENTUM_API_KEY is not set. Set it in your MCP client config (env block) and restart the client.",
        );
      }
    
      const apiUrl = process.env.EJENTUM_API_URL || DEFAULT_API_URL;
    
      let response: Response;
      try {
        response = await fetch(apiUrl, {
          method: "POST",
          headers: {
            Authorization: `Bearer ${apiKey}`,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ query, mode }),
        });
      } catch (err) {
        const detail = err instanceof Error ? err.message : String(err);
        throw new Error(`Network error calling Ejentum API at ${apiUrl}: ${detail}`);
      }
    
      if (!response.ok) {
        const body = await response.text().catch(() => "");
        if (response.status === 401) {
          throw new LogicAPIError(
            401,
            body,
            "Unauthorized (401): check your EJENTUM_API_KEY value. Get one at https://ejentum.com/dashboard.",
          );
        }
        if (response.status === 403) {
          throw new LogicAPIError(
            403,
            body,
            "Forbidden (403): your API key does not have access to this mode. Multi modes require the Haki tier.",
          );
        }
        if (response.status === 429) {
          throw new LogicAPIError(
            429,
            body,
            "Rate limit exceeded (429): you have hit your tier's request limit. See https://ejentum.com/pricing.",
          );
        }
        throw new LogicAPIError(
          response.status,
          body,
          `Ejentum API returned ${response.status}: ${body.slice(0, 200)}`,
        );
      }
    
      let parsed: unknown;
      try {
        parsed = await response.json();
      } catch {
        throw new Error("Ejentum API returned invalid JSON");
      }
    
      if (!Array.isArray(parsed) || parsed.length === 0) {
        throw new Error(
          `Ejentum API returned unexpected shape (expected non-empty array): ${JSON.stringify(parsed).slice(0, 200)}`,
        );
      }
    
      const item = parsed[0] as LogicAPIResponseItem;
    
      // Bracket access is required because the `anti-deception` field name contains a hyphen.
      // Dot access (item.anti-deception) would parse as `item.anti - deception` and silently break.
      const injection = item[mode];
    
      if (typeof injection !== "string" || injection.length === 0) {
        throw new Error(
          `Ejentum API response missing or empty "${mode}" field. Got: ${JSON.stringify(item).slice(0, 200)}`,
        );
      }
    
      return injection;
    }
  • Type definition for HarnessMode that includes 'memory' as one of the allowed modes.
    export type HarnessMode = "reasoning" | "code" | "anti-deception" | "memory";
  • Input schema (Zod) for all harness tools including harness_memory - validates the query string parameter.
    const querySchema = {
      query: z
        .string()
        .min(1, "query must be a non-empty string")
        .describe(
          "1-2 sentence framing of the task you need the harness for. Be specific about WHAT you are trying to do, not what tool you want. Good: 'diagnose why a microservice returns 503s under load'. Bad: 'help me think'.",
        ),
    };
  • src/index.ts:55-77 (registration)
    Loop that registers all harness tools (including harness_memory) onto the MCP server via server.tool().
    for (const harness of HARNESSES) {
      server.tool(
        harness.name,
        harness.description,
        querySchema,
        async ({ query }: { query: string }) => {
          try {
            const injection = await callHarness(query, harness.mode);
            return {
              content: [{ type: "text" as const, text: injection }],
            };
          } catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            return {
              content: [
                { type: "text" as const, text: `Ejentum harness error: ${message}` },
              ],
              isError: true,
            };
          }
        },
      );
    }
Behavior5/5

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

No annotations provided, so the description fully covers behavioral traits: it returns a perception scaffold with components (perception failure, detection procedure, suppression vectors), warns about scaffold paralysis, and instructs to absorb internally. No contradictions.

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

Conciseness3/5

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

The description is verbose with multiple paragraphs and a long list of trigger queries. While front-loaded with purpose, it could be more concise without losing clarity. Well-structured but not minimal.

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?

Given no output schema, the description adequately explains the result (perception scaffold) and how to use it. It covers usage, warnings, and constraints, making it complete for the tool's complexity.

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

Parameters4/5

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

Only one parameter (query) with 100% schema coverage. The description adds value by specifying the required framing ('I noticed X, this might mean Y, sharpen Z'), going beyond the schema's generic description.

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 tool is for sharpening already-formed perceptions about conversation state, user behavior, etc. It distinguishes itself from fact extraction, summarization, and other tasks, making its purpose specific and distinct from siblings.

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

Usage Guidelines5/5

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

Explicitly lists when to call (with trigger queries), provides a detailed 'when not to call' section (e.g., fact extraction, write-heavy tasks), and gives guidance on how to format queries (1-2 sentence framing).

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/ejentum/ejentum-mcp'

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