Skip to main content
Glama

pnlcs-mcp

Model Context Protocol 서버로, 오픈소스 결제 패널 PNLCS용입니다. Claude Code, Claude Desktop, Cursor, VS Code 또는 다른 MCP 클라이언트를 PNLCS 설치본에 연결하고 일상적인 영어로 작업하세요:

"어떤 인보이스가 연체되었나요?" — "이 고객의 서비스와 도메인을 보여주세요." — "오늘 사기로 보류된 주문이 있나요?" — "ada@example.com의 도메인 갱신에 관한 티켓을 열어주세요."

의존성 제로. 서버는 이미 보유한 PNLCS 관리자 API와 통신하는 하나의 작은 Node 프로세스입니다. PNLCS 쪽에는 아무것도 설치되지 않습니다.

  • npm: pnlcs-mcp

  • 요구 사항: AI 클라이언트가 실행되는 머신의 Node 18+

  • 전송: stdio (클라이언트가 생성 — 포트 없음, 호스팅할 것 없음)


1. PNLCS에서 API 자격 증명 만들기

  1. PNLCS 설치본의 관리자 영역에 로그인합니다.

  2. 구성 → API 자격 증명으로 이동합니다.

  3. 만들기를 클릭하고 mcp 같은 이름을 지정한 다음 표시되는 두 값을 복사합니다:

    • 식별자 — 자격 증명의 사용자 이름

    • 비밀 키 — 한 번만 표시되며 안전한 곳에 보관하세요

서버에 필요한 것은 이 두 값뿐이며, 세 가지 환경 변수를 통해 전달됩니다:

Variable

Value

PNLCS_URL

설치본 주소, 예: https://billing.example.com

PNLCS_IDENTIFIER

자격 증명의 식별자

PNLCS_SECRET

자격 증명의 비밀 키

PNLCS_ALLOW_WRITES

선택 사항. 1로 설정하면 쓰기 도구도 활성화됩니다(아래 참조)


Related MCP server: WHMCS MCP Server

2. 클라이언트 연결하기

Claude Code (CLI)

명령 하나면 됩니다:

claude mcp add pnlcs \
  --env PNLCS_URL=https://billing.example.com \
  --env PNLCS_IDENTIFIER=your_identifier \
  --env PNLCS_SECRET=your_secret \
  -- npx -y pnlcs-mcp

쓰기 도구도 원한다면 --env PNLCS_ALLOW_WRITES=1을 추가하세요. .mcp.json을 통해 팀과 항목을 공유하려면 --scope project를 사용하세요. (비밀 키는 커밋된 파일이 아닌 셸 환경에 넣으세요). claude mcp list로 확인하고, claude mcp remove pnlcs로 제거하세요.

Claude Desktop

claude_desktop_config.json을 편집하세요 (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\):

{
  "mcpServers": {
    "pnlcs": {
      "command": "npx",
      "args": ["-y", "pnlcs-mcp"],
      "env": {
        "PNLCS_URL": "https://billing.example.com",
        "PNLCS_IDENTIFIER": "your_identifier",
        "PNLCS_SECRET": "your_secret"
      }
    }
  }
}

Claude Desktop을 다시 시작하면 도구가 망치 아이콘 아래에 나타납니다.

Cursor

설정 → MCP → 새 전역 MCP 서버 추가로 이동하거나, 프로젝트에 .cursor/mcp.json을 만드세요(위의 Claude Desktop과 동일한 JSON 형태).

VS Code (Copilot 에이전트 모드)

.vscode/mcp.json을 만드세요:

{
  "servers": {
    "pnlcs": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "pnlcs-mcp"],
      "env": {
        "PNLCS_URL": "https://billing.example.com",
        "PNLCS_IDENTIFIER": "your_identifier",
        "PNLCS_SECRET": "your_secret"
      }
    }
  }
}

그 외 (Windsurf, Cline, Zed, ...)

stdio 서버를 생성할 수 있는 모든 MCP 클라이언트는 동일한 세 가지를 사용합니다: 명령 npx, args ["-y", "pnlcs-mcp"], 그리고 위의 환경 변수들입니다. git 체크아웃에서는 node mcp/server.js도 동일하게 작동합니다.


3. 도구

읽기 도구 — 항상 사용 가능

Tool

What it answers

get_stats

고객, 주문, 인보이스 및 수익 합계

get_health

설치본 자체의 상태

list_clients

고객 목록, 이름/이메일/회사로 검색 가능, 페이지 매김 지원

get_client

연락처가 포함된 단일 고객, clientid 또는 email로 조회

list_client_services

한 고객의 호스팅 서비스

list_client_domains

한 고객의 도메인

list_invoices

인보이스; status(draft, unpaid, paid, overdue, cancelled) 또는 고객으로 필터링

get_invoice

라인 항목이 포함된 단일 인보이스

list_orders

주문; status(pending, active, fraud, cancelled)로 필터링

list_tickets

지원 티켓; 상태별 필터링

get_ticket

답변과 메모가 포함된 단일 티켓

get_ticket_counts

상태별 티켓 합계

list_transactions

결제 내역, 최신순

list_products

제품 카탈로그

get_activity_log

최근 관리자 및 시스템 활동

쓰기 도구 — PNLCS_ALLOW_WRITES=1인 경우에만

Tool

What it does

add_client

고객 생성; password2를 사용하면 포털 로그인도 함께 생성

create_invoice

하나 이상의 라인 항목으로 고객에게 인보이스 발행

add_invoice_payment

결제 기록; 금액이 충당되면 인보이스를 지불 완료로 표시

open_ticket

지원 티켓 열기

add_ticket_reply

티켓에 답변

suspend_service

호스팅 서비스를 해당 서버에서 일시 중지

unsuspend_service

일시 중지 해제

플래그가 없으면 쓰기 도구는 단순히 숨겨지는 것이 아닙니다. 호출 시 HTTP 요청이 발생하기 전에 거부됩니다. 보고용으로 설정된 어시스턴트는 일시 중지 버튼조차 볼 수 없습니다. 플래그를 설정하지 않기만 하면 보고용 설정을 읽기 전용으로 만들 수 있습니다.


4. 보안 참고 사항

  • 비밀 키는 AI 클라이언트가 실행되는 머신과 PNLCS 설치본 사이에서만 이동하며, 관리자 화면이 사용하는 것과 동일한 HTTPS API를 통해 전송됩니다. 모델 제공자에게는 절대 전송되지 않습니다. 모델은 도구 결과만 봅니다.

  • MCP에는 전용 API 자격 증명을 사용하는 것이 좋습니다. 그래야 해당 자격 증명만 별도로 해지할 수 있습니다.

  • PNLCS는 API 자격 증명을 속도 제한합니다(자격 증명당 분당 300회 요청). 따라서 폭주하는 에이전트가 설치본을 마구 때릴 수 없습니다.

  • 어시스턴트가 실제로 장부를 변경하기를 원하지 않는 한 PNLCS_ALLOW_WRITES를 끈 상태로 유지하고, 무언가를 생성하거나 변경하는 도구 호출을 승인하기 전에 어시스턴트가 제안하는 내용을 읽어보세요.

5. 문제 해결

Symptom

Cause

모든 도구가 Set PNLCS_URL, PNLCS_IDENTIFIER and PNLCS_SECRET.라고 응답합니다.

세 변수 중 하나가 클라이언트 구성에서 누락되었습니다.

모든 도구가 Invalid API secret이라고 응답합니다.

식별자/비밀 키 쌍이 잘못되었거나 자격 증명이 비활성화되었습니다.

PNLCS did not answer within 30 seconds

이 머신에서 설치본에 연결할 수 없습니다 — URL과 방화벽을 확인하세요.

클라이언트에 도구가 표시되지 않음

구성 편집 후 클라이언트를 다시 시작하세요. 위의 stderr 줄이 있는지 MCP 로그를 확인하세요.

쓰기 도구가 없음

그것이 기본값입니다 — PNLCS_ALLOW_WRITES=1을 설정하세요.

6. 테스트

npm test는 오프라인 테스트 스위트를 실행합니다. 실제 서버 프로세스를 생성하고 실제 프로토콜로 통신하며, 모든 도구의 HTTP 형태를 로컬 스텁과 대조합니다. 또한 양방향 쓰기 게이트, 이전 프로토콜 버전의 배치 요청, 버전 협상, 타임아웃 및 종료 시 대기 중인 요청 처리를 확인합니다.

node test/live.mjs는 실제 설치본을 대상으로 모든 도구를 실행합니다. 데모를 대상으로 지정하세요. 절대 프로덕션 장부를 대상으로 하지 마세요. 쓰기 도구를 위해 명확한 이름의 임시 데이터를 생성하고 도구마다 PASS/FAIL 줄을 하나씩 출력합니다.

개발

이 패키지는 PNLCS 모노레포의 mcp/ 아래에서 개발됩니다. 이 저장소는 독립 실행형 배포 미러이며 항상 npm에 게시된 버전과 일치합니다.

Available Tools

15 tools
get_activity_logC

Recent admin and system activity.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitnumNoEntries to return, default 25
limitstartNoOffset to start from

TDQS

C2.9/5.0
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. 'Recent' implies a recency filter and 'activity' implies a log of events, but the description does not state whether this is read-only, what an activity entry contains, whether both admin and system events are returned, or how the recency window is determined. The behavior is only minimally conveyed.

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 very short and contains no wasted words, which is efficient. However, it is a single fragment with no structure or elaboration, and it is shorter than is needed to provide a full picture. It is concise but under-specified.

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

Completeness3/5

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

For a simple paginated activity log with optional limit/offset parameters, the description is minimally viable: it names the resource and the schema covers the parameters. But with no annotations and no output schema, the description leaves gaps about the return shape, the meaning of 'recent', and the exact scope of 'admin and system'.

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 description coverage is 100%: both limitnum and limitstart include clear inline descriptions. The tool description adds no parameter information, so the baseline score of 3 applies — the schema alone adequately documents the parameters.

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

Purpose4/5

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

The description identifies a clear resource — recent admin and system activity — which distinguishes it from sibling tools focused on stats, health, clients, or invoices. It lacks an explicit verb like 'list' or 'get', but the noun phrase is unambiguous enough that an agent can infer the action from the tool name and context.

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

Usage Guidelines2/5

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

There is no guidance on when to use this tool versus siblings such as get_stats, get_health, or list_tickets. No context or exclusions are provided, so the agent must rely on the name and the terse description alone to decide if this is the right tool.

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

get_clientA

One client with contacts, by clientid or email.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailNoClient email, instead of the id
clientidNoClient id

TDQS

A3.5/5.0
Behavior3/5

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

No annotations are provided, so the description carries the burden. It does say the result includes contacts and that lookup is by clientid or email, but it does not disclose behavior when neither or both identifiers are supplied, error handling, or return format details. For a read operation this is adequate but thin.

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 extremely short and every word earns its place; the key facts are front-loaded. There is no redundancy or filler.

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

Completeness3/5

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

For a simple lookup tool, the description plus schema covers purpose, key fields, and that contacts are included. However, the schema marks both parameters optional and the description does not state that at least one is required, nor what happens on no match. This is a noticeable gap for an agent deciding how to call it.

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?

The input schema already describes both parameters with 100% coverage, so the baseline is 3. The description adds the 'or' relationship (clientid or email), which is mildly useful confirmation. It does not add formats, defaults, or precedence.

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

Purpose4/5

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

The phrase 'One client with contacts' clearly identifies the operation as retrieving a single client and its contacts, and it names the lookup fields. It distinguishes from plural list tools even though it doesn't explicitly name them. The verb is implied by the tool name rather than stated in the description, so slightly short of a 5.

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?

No explicit when-to-use or when-not-to-use guidance is present. 'One client' implies the tool is for single-record lookups rather than list operations, but alternatives such as list_clients are not mentioned. Usage context is only implied.

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

get_healthB

Health of the PNLCS install itself.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.2/5.0
Behavior2/5

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

With no annotations, the description carries the burden of behavioral disclosure, but it only states the domain (PNLCS health). It does not mention that this is a read-only check, what fields or statuses are returned, or any operational behavior.

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?

A single sentence with no filler or repetition. The essential scope is front-loaded and every word contributes.

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

Completeness3/5

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

For a zero-parameter health endpoint, the description is minimally viable, but without an output schema it leaves the return format unspecified. The agent can invoke it correctly, yet has no knowledge of what the health response will contain.

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?

There are zero parameters and the schema already documents an empty input object, so the description does not need to explain parameters. Baseline 4 applies because there is nothing to clarify.

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

Purpose4/5

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

The description clearly identifies the resource (the PNLCS install) and the subject (its health), and 'itself' distinguishes it from the data-focused sibling tools. It lacks an explicit verb such as 'get' or 'retrieve', so it misses the top criterion.

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

Usage Guidelines2/5

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

No guidance is given about when to choose this tool over siblings like get_stats, nor any conditions or exclusions. The phrase 'install itself' weakly implies a health-check use case, but that is not enough to guide tool selection.

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

get_invoiceC

One invoice with its line items.

ParametersJSON Schema
NameRequiredDescriptionDefault
invoiceidYesInvoice id

TDQS

C2.9/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It only states that a single invoice and its line items are returned, without mentioning failure behavior, not-found responses, authorization, or response structure. This is too sparse for a tool with zero annotation coverage.

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?

The description is extremely concise and front-loaded, with every word contributing. Its brevity is appropriate for a simple single-resource getter, though it may be too terse to serve as a complete standalone explanation.

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

Completeness2/5

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

With no annotations and no output schema, the description is the only source of behavioral context. It covers the basic return object but omits surrounding context such as how to handle unknown IDs, relationship to list_invoices, and any expected response details. For such a low-complexity tool this is borderline viable, but it remains under-specified.

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?

The schema has 100% description coverage for the only parameter, invoiceid, and the description does not need to add much. The text does not enrich parameter meaning beyond the schema, but the schema already documents the parameter sufficiently.

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

Purpose4/5

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

The description clearly identifies the resource (invoice) and scope ('one invoice') and adds the useful detail that line items are included. It lacks an explicit verb, but the tool name 'get_invoice' supplies the action. It distinguishes from list_invoices by emphasizing a single invoice, though not explicitly.

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

Usage Guidelines2/5

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

The description gives no guidance on when to use this tool versus alternatives such as list_invoices. An agent must infer that get_invoice is for a single invoice by ID while list_invoices is for multiple invoices. No exclusions, preconditions, or alternative routing are mentioned.

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

get_statsB

Business overview: client, order, invoice and revenue totals.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.2/5.0
Behavior2/5

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

No annotations are provided, so the description must carry the full behavioral disclosure burden. It only says the tool provides totals, but does not explain whether these are counts, currency sums, point-in-time snapshots, or how the data is aggregated or scoped.

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 a single compact sentence that front-loads the main concept and uses the rest to name the four metric categories. There is no filler or repetition, making it highly efficient for a zero-parameter tool.

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

Completeness3/5

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

With no output schema and no annotations, the description is the only source of information about what the tool returns. It names the relevant metric areas but leaves ambiguity about the exact meaning of 'totals' and the response structure, which is a notable gap.

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?

The tool has zero parameters and the input schema has no properties, so there are no parameter semantics for the description to enhance. The baseline of 4 applies because there is no parameter documentation burden.

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

Purpose4/5

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

The description clearly identifies the tool as returning a business overview with client, order, invoice, and revenue totals. It uses a distinct aggregate scope, which separates it from the more granular sibling tools like list_invoices or get_client, though it does not explicitly state a verb.

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

Usage Guidelines2/5

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

There is no guidance on when to use this tool versus alternatives such as list_orders, get_ticket_counts, or list_invoices. The description implies it is for high-level summary numbers, but it never states exclusions or points users toward sibling tools for detailed data.

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

get_ticketB

One ticket with its replies and notes.

ParametersJSON Schema
NameRequiredDescriptionDefault
ticketidYesTicket id

TDQS

B3.4/5.0
Behavior3/5

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

No annotations are provided, so the description carries the disclosure burden. It reveals that the returned ticket includes replies and notes, which is useful, but it does not mention read-only behavior, error conditions, or whether replies and notes are always included.

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?

The description is very short and contains no filler. It front-loads the key scope ('One ticket') and adds value with 'replies and notes', though it is more of a noun phrase than a complete sentence.

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

Completeness3/5

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

For a single-parameter, single-record retrieval tool, the description is minimally adequate: it identifies the resource and included content. However, since there is no output schema, the description could usefully mention missing-ticket behavior, response shape, or caveats about replies and notes.

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 description coverage is 100%, and the ticketid parameter is documented as 'Ticket id'. The description adds no parameter-level detail, but none is necessary because the schema already fully covers the only parameter.

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

Purpose4/5

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

The description states the tool returns one ticket and explicitly includes replies and notes; the verb 'get' is carried by the tool name. The phrase 'one ticket' differentiates it from list_tickets and get_ticket_counts, though the description itself lacks an explicit action verb.

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 word 'One' implies a singular ticket lookup, which provides some usage context, but the description never explicitly says when to use this tool instead of list_tickets or get_ticket_counts. No alternatives or exclusions are named.

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

get_ticket_countsB

Ticket totals per status.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It reveals that the tool returns aggregate counts grouped by status, but it does not clarify whether the operation is read-only, what the response format is, whether filters exist, or whether the counts cover all tickets globally.

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?

The description is extremely short and contains no filler, making it easy to parse quickly. It is appropriately front-loaded, though the brevity borders on under-specification rather than structured completeness.

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

Completeness2/5

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

With no output schema and no annotations, the description leaves unresolved what the response looks like and how the counts are scoped. For a zero-parameter tool, complexity is low, but the lack of return-format details makes it incomplete for confident agent invocation.

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?

The tool has zero parameters, so the description does not need to explain parameter behavior. The empty input schema is self-explanatory, and the baseline for zero-parameter tools is 4.

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

Purpose4/5

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

The description clearly identifies the resource (tickets) and the aggregation (totals per status), which distinguishes it from list_tickets and get_ticket. It lacks an explicit verb such as 'get' or 'return,' so it falls just short of a perfect score.

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

Usage Guidelines2/5

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

There is no guidance about when to use this tool versus alternatives like get_stats or list_tickets. An agent must infer the intended use case from the phrase alone, with no exclusions or sibling-tool comparisons.

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

list_client_domainsC

Domains that belong to one client.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientidYesClient id

TDQS

C2.5/5.0
Behavior2/5

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

With no annotations provided, the description carries full responsibility for disclosing behavior, but it only states what the returned data represents. It does not mention that the operation is read-only, whether the client must exist, pagination, ordering, or error behaviors. The description adds no transparency beyond the input schema.

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 very short and free of fluff, but it is an incomplete sentence fragment rather than a structured statement. It conveys a single piece of information but lacks the polish of a fuller, well-structured description. It is concise but not necessarily well-formed.

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

Completeness2/5

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

Given the absence of an output schema and annotations, the description must explain what the tool returns and how it behaves, but it only states that the result is a client's domains. There is no information on return format, pagination, or error scenarios. For a simple tool this is a minimal but incomplete definition; an agent might correctly call it but cannot anticipate the response shape or failure modes.

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?

The input schema fully describes the only parameter (clientid) with a baseline description, and schema coverage is 100%. The tool description adds no additional meaning to the parameter, so the baseline of 3 is appropriate. The agent can infer that clientid identifies the client whose domains are listed, but no format or edge-case details are given.

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

Purpose3/5

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

The description identifies a specific resource (domains) and scope (one client), indicating the tool's purpose from context. However, it is a noun phrase, not a verb-driven statement, so the operation (list) must be inferred from the tool name rather than the description. It does not explicitly differentiate itself from sibling tools, though the domain focus makes it distinct.

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

Usage Guidelines2/5

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

No guidance is provided about when to use this tool versus alternatives such as list_client_services or get_client. There are no stated conditions, prerequisites, or exclusions. An agent must rely entirely on the tool name and schema to infer suitability.

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

list_clientsA

List clients, newest first. Optional text search and paging.

ParametersJSON Schema
NameRequiredDescriptionDefault
searchNoMatch against name, email or company
statusNoactive, inactive or closed
limitnumNoPage size, default 25
limitstartNoOffset to start from

TDQS

A3.8/5.0
Behavior3/5

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

With no annotations provided, the description carries the behavioral disclosure burden. It reveals sort order ('newest first') and optional search/paging, but does not mention the status filter behavior, response shape, or pagination limits beyond the schema.

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?

Two short sentences deliver the core action, ordering, and optional capabilities with no wasted words. The most important information is front-loaded.

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 simple listing tool with fully documented parameters, the description is largely sufficient. It covers ordering, search, and paging, and the schema fills in parameter details. It does not describe the return format, but for a list operation the expected output is reasonably implied.

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 description coverage is 100%, so the baseline is 3. The description adds only minimal mapping by referring to 'text search and paging,' but does not explain the status filter or the exact pagination parameter semantics beyond what the schema already provides.

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 states the operation precisely: 'List clients, newest first.' It clearly identifies the resource (clients), the action (list), and an ordering trait that distinguishes it from singular retrieval tools like get_client.

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 for browsing or searching clients, but it does not explicitly state when to use this tool over alternatives like get_client. It gives context for optional search and paging but no exclusion criteria.

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

list_client_servicesC

Hosting services that belong to one client.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientidYesClient id

TDQS

C2.9/5.0
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It only restates that the result is hosting services for one client and does not mention return format, pagination, ordering, error behavior, permissions, or side effects.

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?

The description is very short, with no filler, and the key scoping information ('one client') is front-loaded. It is efficient, though it reads more like a noun-phrase definition than a complete tool instruction.

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

Completeness3/5

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

For a one-parameter read-only list tool, this is minimally viable: an agent can infer the basic operation and the required parameter. However, it lacks behavioral details such as response shape or limits and does not differentiate from closely related sibling tools like list_client_domains.

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?

The input schema already documents clientid as an integer 'Client id' with 100% coverage. The description adds minimal semantic context by saying the services belong to one client, but it does not elaborate on parameter constraints, format, or edge cases.

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

Purpose4/5

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

The description identifies the resource ('hosting services') and the scope ('belong to one client'), which distinguishes it from sibling tools like list_client_domains or list_invoices. It is clear what entity is returned, though it lacks an explicit verb and relies on the tool name 'list' for the action.

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

Usage Guidelines2/5

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

No guidance is provided on when to use this tool versus sibling list tools, no alternatives are named, and there are no exclusionary conditions. The only implicit cue is 'one client,' which maps to the required clientid parameter.

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

list_invoicesB

List invoices. Filter by status (draft, unpaid, paid, overdue, cancelled) or client.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoInvoice status
useridNoOnly this client
limitnumNoPage size, default 25
limitstartNoOffset to start from

TDQS

B3.1/5.0
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It does not mention pagination behavior, default limits, ordering, response format, or whether filters are optional or mutually exclusive. 'List' implies a read operation, but key behavioral details are missing.

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 two short sentences with no filler. The core action is front-loaded, and the filter options are efficiently summarized.

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

Completeness2/5

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

The tool has 4 parameters, no output schema, and no annotations, so the description must compensate with more behavioral context. It omits important operational details such as pagination defaults, what response shape to expect, and whether filters can be combined. The description is adequate for identifying the tool but not for safe autonomous invocation without additional inference.

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?

Schema description coverage is 100%, so the baseline is 3. The description adds value by enumerating specific status values (draft, unpaid, paid, overdue, cancelled) and clarifying that 'userid' means client. This goes beyond the schema's generic descriptions.

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

Purpose4/5

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

The description states a specific verb and resource ('List invoices') and lists filter options, clearly distinguishing it from the sibling get_invoice. However, it does not explicitly name the sibling or note when the singular retrieval tool should be used instead.

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

Usage Guidelines2/5

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

The description implies usage by stating the action and filters, but it provides no explicit guidance on when to use this tool versus alternatives like get_invoice. There is no mention of exclusions, prerequisites, or conditions that would route an agent to a different tool.

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

list_ordersA

List orders. Filter by status (pending, active, fraud, cancelled) or client.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoOrder status
useridNoOnly this client
limitnumNoPage size, default 25
limitstartNoOffset to start from

TDQS

A3.6/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden. 'List orders' implies read-only behavior, but the description does not explicitly state that this operation is non-destructive, nor does it mention pagination behavior or the default page size. The schema hints at these, but the description itself adds no behavioral context.

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?

Two short clauses deliver the core purpose and filters with zero filler. The key action is front-loaded and every word earns its place.

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 the tool's simplicity, the description is mostly complete for selecting and invoking it. The schema covers all parameters including pagination defaults, and the description covers allowed statuses. A minor gap is that it does not explicitly say what happens when no filters are supplied or that results are paginated, but this is reasonably inferable from the schema.

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?

Schema coverage is 100%, so the baseline is 3. The description adds value by enumerating the allowed status values ('pending, active, fraud, cancelled') and mapping 'client' to the userid parameter, which goes beyond the schema's generic 'Order status' and 'Only this client' descriptions.

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 states a specific verb and resource ('List orders') and adds the key filtering dimensions (status and client). The allowed statuses are even enumerated, making the tool's purpose unambiguous and distinguishing it from other list tools like list_invoices or list_clients.

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

Usage Guidelines2/5

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

The description gives no explicit when-to-use guidance or alternatives. It simply states what the tool does, leaving the agent to infer that this is the tool for listing orders based on the name alone.

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

list_productsC

The product catalogue.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

C2.1/5.0
Behavior1/5

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

No annotations are provided and the description does not disclose any behavioral traits such as whether the operation is read-only, paginated, filtered, or what data it returns. The phrase 'The product catalogue' is entirely static and offers no insight into how the tool behaves when invoked.

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

Conciseness2/5

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

The description is four words long, but brevity here is under-specification rather than conciseness. It lacks a verb, and a proper tool description should at least say 'List products in the catalogue.' The structure does not front-load any actionable information.

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

Completeness2/5

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

For a zero-parameter tool with no output schema, the description is still inadequate. It does not explain what a product catalogue entry contains, whether the result is a list or a single item, or how this tool differs from the several other list_* tools. An agent would have to guess at the return value and behavior.

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?

The tool takes zero parameters, and the schema is empty, so there are no parameter semantics to document. Per the rubric, a zero-parameter tool gets a baseline of 4, and there is no gap for the description to compensate for.

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

Purpose2/5

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

The description 'The product catalogue' is a noun phrase that identifies the subject but does not state any verb or action. It essentially restates the resource implied by the tool name 'list_products' without clarifying that the tool returns a list of products. This is close to a tautology and does not distinguish it from other list tools.

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

Usage Guidelines2/5

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

There is no guidance on when to use this tool versus the many sibling list tools such as list_clients, list_invoices, list_orders, or list_tickets. The description provides no context about typical use cases, exclusions, or alternatives, leaving the agent to infer everything from the name alone.

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

list_ticketsB

List support tickets. Filter by status.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoTicket status, e.g. open, answered, closed
limitnumNoPage size, default 25
limitstartNoOffset to start from

TDQS

B3.3/5.0
Behavior2/5

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

With no annotations present, the description carries the full burden of behavioral disclosure. It indicates a read-style list operation, but does not describe pagination behavior, response shape, ordering, or any side effects. It adds little beyond what the tool name already suggests.

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?

Two short, front-loaded sentences with no filler. Every phrase earns its place, making the description easy to consume quickly.

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

Completeness3/5

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

For a simple list tool with fully documented parameters, the core call is understandable. However, with no output schema and no annotations, the description leaves the return shape implied and does not help an agent choose between list_tickets, get_ticket, and get_ticket_counts.

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 description coverage is 100%, so the schema already documents status, limitnum, and limitstart. The description reinforces the intended use of 'status' for filtering, but provides no additional semantic detail for the pagination parameters.

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

Purpose4/5

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

The description uses a specific verb ('List') and resource ('support tickets'), and adds a useful qualifier ('Filter by status'). This clearly identifies the core operation, though it does not explicitly distinguish itself from ticket-related siblings like get_ticket or get_ticket_counts.

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?

'Filter by status' provides a concrete usage context and implies this is the tool for retrieving a filtered ticket list. However, it gives no explicit when-to-use or when-not-to-use guidance and does not name alternative tools, so selection logic is left mostly to inference.

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

list_transactionsB

Payment transactions, newest first.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientidNoOnly this client
limitnumNoPage size, default 25
limitstartNoOffset to start from

TDQS

B3.1/5.0
Behavior3/5

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

With no annotations, the description carries the disclosure burden. It does add one meaningful behavioral trait: results are ordered newest first. It does not explicitly state that this is a read-only list operation or describe pagination/response behavior beyond what the schema hints at, but the tool name and 'list' semantics imply safe retrieval.

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?

The description is very short, contains no filler, and front-loads the resource and ordering. It is efficient, though it is a fragment rather than a complete sentence, so it slightly sacrifices completeness for brevity.

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

Completeness2/5

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

There is no output schema and no annotations, so the description should provide richer context about what a payment transaction record contains and what the response looks like. It only states the resource and sort order, which is enough to guess tool selection but not enough to fully anticipate results or interpret the response.

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 description coverage is 100%, with clientid, limitnum, and limitstart each already documented. The description adds no parameter semantics, so it does not go beyond the baseline established by the schema.

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

Purpose4/5

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

The description clearly identifies the resource ('payment transactions') and a key differentiator ('newest first'). However, it lacks an explicit verb and does not contrast with neighboring listing tools like list_invoices or list_orders, so it stops short of full sibling differentiation.

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

Usage Guidelines2/5

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

No guidance is given about when to choose this tool over alternatives such as list_invoices or list_orders. The only implied usage is that it returns payment transactions, with no exclusions, prerequisites, or context about whether a clientid is expected.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 15 tool updatesv1.0.4
    • First observedget_activity_log
    • First observedget_client
    • First observedget_health
    • First observedget_invoice
    • First observedget_stats
    • First observedget_ticket
    • First observedget_ticket_counts
    • First observedlist_client_domains
    • First observedlist_client_services
    • First observedlist_clients
    • First observedlist_invoices
    • First observedlist_orders
    • First observedlist_products
    • First observedlist_tickets
    • First observedlist_transactions

TDQS

B3.3/5.0

Scored across 15 tools

Disambiguation5/5

Each tool targets a distinct resource or summary view: health/stats/activity are clearly separate from client, invoice, order, ticket, transaction, and product listings. There is little overlap, and the get_/list_ split makes singular detail vs collection retrieval obvious.

Naming Consistency5/5

Tool names consistently use lowercase snake_case with get_ for single items/details and list_ for collections. The compound list_client_services and list_client_domains still follow the same predictable verb_noun pattern as the rest of the set.

Tool Count5/5

Fifteen tools is at the upper end of the ideal range but every one maps to a distinct and useful view of the PNLCS domain, from clients and invoices to tickets and activity. There is no obvious redundancy or filler.

Completeness4/5

As a read-only business overview server, the surface is broad and coherent: clients, services, domains, invoices, orders, tickets, transactions, products, stats, health, and activity are all exposed. Minor gaps such as no get_order, get_product, or get_transaction detail views, and no mutation endpoints, keep it from being fully complete.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to manage WHM hosting accounts and server administration tasks including account management, server stats, updates, SSL, backups, and email through a secure API.
    11
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to administrate WHMCS installations through the External API, providing ~50 tools for clients, billing, orders, services, domains, support, and aggregators with safety features and governance.
    29 npm
    3
    ISC
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to manage cPanel hosting accounts including DNS, email, databases, SSL, files, security, and more through natural language using cPanel's UAPI and API2.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Connect Claude, ChatGPT, and Cursor to your live WHMCS. 96 tools, 18 workflow prompts, 24 resources. Runs as a Docker container (or Linux binary) that talks to the WHMCS API from outside — nothing installed inside WHMCS. OAuth 2.0 for Claude.ai and ChatGPT web, bearer tokens for Cursor. dryRun on every write. 14-day trial, no card.
    13 npm
    2
    MIT