license-mcp
Supports npm projects by reading package-lock.json and optionally querying registry.npmjs.org for license metadata, enabling dependency license inventory, policy checks, and notices generation.
Supports pnpm lockfiles (pnpm-lock.yaml) to inventory direct and transitive dependencies, normalize their licenses, and evaluate them against a license policy.
Supports Poetry lockfiles (poetry.lock) to inventory Python dependencies, using installed dist-info metadata when available and reporting license verdicts.
Provides optional online license lookups from pypi.org for Python packages when online=true, while keeping network access off by default.
Normalizes dependency licenses into SPDX expressions, including AND/OR/WITH, parentheses, LicenseRef, deprecated identifiers, and OR choices against an allow list.
Supports Yarn lockfiles (yarn.lock) to inventory Node dependencies, group them by normalized SPDX license, and check them against policy.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@license-mcpwhat licenses are my dependencies under? show me anything unknown"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
license-mcp
Ask your AI agent what licenses your dependencies are under, and whether you can ship the thing.
license-mcp is an MCP server that reads a project's lockfiles
(uv.lock, poetry.lock, requirements.txt, package-lock.json, pnpm-lock.yaml, yarn.lock,
Cargo.lock, go.sum), works out every dependency's license mostly offline, normalises it to
SPDX, and gives you an inventory, ok / needs review / violation verdicts against your policy,
compatibility guidance, and a draft THIRD-PARTY-NOTICES.md.
How it differs from the other license MCP servers
Several servers already do part of this: license-scan-mcp scans npm lockfiles for GPL/AGPL/unknown, license-check-mcp answers "does license A fit license B" from the OSADL matrix, and LicenseGuard checks SBOMs. What this one adds:
It reads what is actually installed. Licenses come first from the Python dist-info in your venv,
node_modules/*/package.json, or~/.cargo/registry, then from the lockfile, and only then (and only if you passonline=true) from PyPI / npm / crates.io. No network by default.Every package reports its source (
installed metadata (License-Expression),lockfile (package-lock.json),online: PyPI, ornone), and UNKNOWN is explicit, never guessed.Eight lockfile formats across Python, Node, Rust and Go in one call, with direct vs transitive counts, using hand-written parsers (no heavy dependencies).
Its own SPDX engine:
AND/OR/WITH, parentheses,LicenseRef-, deprecated ids (GPL-2.0becomesGPL-2.0-only), and messy strings (MIT License,Apache 2,GPLv2+, trove classifiers).ORexpressions are resolved against your allow list.A small, documented compatibility table whose answers cite the rule and the reasoning.
Related MCP server: license-sentinel
What it looks like
Real output from the project's own venv (51 locked packages, nothing downloaded):
> license_inventory
Packages: 51 (6 direct, 45 transitive)
License sources: installed metadata 41, none 10
By license (9 distinct):
MIT - 23 package(s) (5 direct, 18 transitive) [permissive]
BSD-3-Clause - 9 package(s) (0 direct, 9 transitive) [permissive]
Apache-2.0 OR BSD-3-Clause - 1 package(s) [permissive] <- cryptography
MPL-2.0 - 1 package(s) (0 direct, 1 transitive) [weak-copyleft]
...
Dual/multi-licensed packages (2) - the OR choice:
cryptography@50.0.2: Apache-2.0 OR BSD-3-Clause -> Apache-2.0
UNKNOWN (10) - no usable license data; not guessed:
httpx2@2.14.0 (transitive): no license information; installed version 2.16.0 differs from locked 2.14.0; ...
> compatibility project_license="GPL-2.0-only" dependency_license="Apache-2.0"
Dependency Apache-2.0 into a project licensed GPL-2.0-only: INCOMPATIBLE
Rule R1: Apache-2.0's patent-termination and indemnity terms are extra restrictions under GPLv2
(FSF: Apache-2.0 is compatible with GPLv3 only)Install
pip install license-mcp # or: uvx license-mcp
claude mcp add license -- uvx license-mcp --dir /path/to/your/projectClaude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"license": {
"command": "uvx",
"args": ["license-mcp", "--dir", "C:\\Users\\you\\code\\my-project"]
}
}
}--dir may be repeated. Without it, the server may read the directory it was started in.
Try asking
"What licenses are my dependencies under? Show me anything unknown."
"Can I ship this as closed source? Check the policy with
permissiveallowed.""Check my dependencies against GPL-3.0-only as the project license."
"Which packages are dual-licensed, and which option should I take if I only accept MIT and Apache-2.0?"
"Is Apache-2.0 code OK in a GPL-2.0-only project?"
"Explain the AGPL in plain words."
"Write a THIRD-PARTY-NOTICES.md for this project."
"Which of my dependencies ship a NOTICE file I have to reproduce?"
"Look up the unknown ones online too." (this passes
online=true)
Tools
Tool | What it does |
| Every dependency's license grouped by normalised SPDX expression with direct/transitive counts, the |
| ok / needs review / violation per package with reasons, from arguments or a |
| May code under license X be used in a project under license Y? compatible / conditional / incompatible / unknown with the rule id (R1-R12) and reasoning. |
| Permissions, conditions and limitations in plain words for about 50 common SPDX ids, plus expressions and |
| A |
| Which dependencies ship a LICENSE / COPYING / NOTICE file in their installed copy, which do not, and which could not be inspected. |
Where licenses come from
Installed copy, if there is one. Python: the venv at
.venv/orvenv/next to the lockfile, or the one you pass aspython=(a venv directory, itspythonexecutable, or asite-packagesdirectory). Fields used, in order:License-Expression, a shortLicensefield, troveLicense ::classifiers (several classifiers combine with AND, the conservative reading). Node:node_modules/<pkg>/package.json(also the pnpm store layout). Rust:$CARGO_HOME/registry/src. An installed copy is used only when its version equals the locked version.The lockfile itself.
package-lock.jsonv2/v3 embedslicense. The others do not.A network lookup, only with
online=true:pypi.org,registry.npmjs.org,crates.ioand nothing else. Concurrency is capped at 6, requests time out after 10 s, responses are capped at 2 MB, redirects are refused, results are cached for an hour, and package names are checked against a strict pattern before they are put into a URL. Go modules have no registry API and stay UNKNOWN.
The first source that gives a recognised license wins. If none does the package is UNKNOWN, and
the reasons are listed.
Policy
Pass allow, deny and project_license as arguments, or put a .license-policy.toml in the project
directory (arguments override the file key by key):
allow = ["MIT", "Apache-2.0", "BSD-*", "public-domain"] # ids, wildcards, or categories
deny = ["AGPL-3.0-only", "source-available"]
project_license = "Apache-2.0"
[exceptions] # packages you have reviewed and accept
"some-lib" = "vendor confirmed MIT by email, ticket 123"
"other@2.0.0" = "used only as a separate CLI"Rules, in order: deny beats allow; with an allow list, anything known and not on it is a violation;
otherwise with a project_license each dependency is judged by the compatibility table (compatible =
ok, conditional = needs review, incompatible = violation); with neither, permissive and public-domain
are ok, weak copyleft (LGPL, MPL, EPL) needs review with linking notes, and strong or network
copyleft, source-available and non-commercial licenses are violations. UNKNOWN and unclassified
licenses always need review. OR takes the best option for you, AND the worst. Categories:
public-domain, permissive, weak-copyleft, strong-copyleft, network-copyleft,
source-available, noncommercial, restricted, proprietary.
The compatibility table
compatibility(project, dependency) asks: can a combined work that includes or links the dependency be
distributed under the project license? The whole table is in the docstring of
compat.py (R0-R12); highlights:
Dependency into project | Verdict | Why |
permissive (MIT, BSD, ISC...) into anything | compatible | keep the notices |
Apache-2.0 into MIT / GPL-3.0 / AGPL | compatible | |
Apache-2.0 into GPL-2.0-only / LGPL-2.1-only | incompatible | patent and indemnity terms are extra restrictions under GPLv2 |
Apache-2.0 into GPL-2.0-or-later | conditional | the combined work must be GPL-3.0 |
MPL-2.0 into GPL / LGPL / AGPL | compatible | MPL section 3.3 secondary license |
MPL-2.0 / LGPL into MIT or closed source | conditional | file-level copyleft / relinking duty |
GPL-3.0 into GPL-2.0-only | incompatible | version conflict |
GPL, AGPL into MIT or closed source | incompatible | the whole combined work would have to be GPL |
AGPL-3.0 into GPL-3.0 | conditional | the network clause stays; AGPL answers always carry a network-clause note |
SSPL / BUSL / Elastic | conditional for closed source, incompatible for open source | source-available, not open source |
CC-BY-NC | incompatible | forbids commercial use |
A project offered under A OR B must be compatible with every option (recipients may pick any); a
dependency offered under X OR Y uses the best option.
Security
Read-only. No tool writes anywhere.
generate_noticesreturns text.Directory sandbox. Every path argument must resolve (symlinks followed) inside a
--dirdirectory (default: the working directory), includingpython=. Symlinks inside a project that point outside it are not read. The one fixed extra location is$CARGO_HOME/registry/src(read-only), used only if aCargo.lockis scanned.Nothing from the inspected project is executed. Python metadata is parsed as text headers (size-capped at 1 MB); the venv's interpreter is never started and its code is never imported.
Bounded inputs. Lockfiles are capped at 40 MB, SPDX expressions at 2000 characters and 40 nesting levels, license files read for copyright lines at 256 KB, lockfile discovery at 3 levels and 40 files. Malformed files produce an error message, never a crash.
Network is opt-in and narrow: see above. No credentials are ever sent or needed.
Honest limits
Not legal advice. The compatibility table and license summaries are guidance written from public license texts and FSF / Apache / MPL / Creative Commons compatibility statements. Read the licenses for anything that matters.
Metadata can lie. A package's declared license can differ from the license file it ships, or be out of date, or be wrong.
find_license_fileshelps you check.UNKNOWN is not "unlicensed". It means no usable license data was found. A package whose
Licensefield holds a pasted license body is UNKNOWN too: license text is never guessed from content.Ambiguous spellings are flagged, e.g. plain
BSDis read as BSD-3-Clause andApache Software Licenseas Apache-2.0; both are reported as approximate, andcheck_policymakes them "needs review".Multiple trove classifiers are read as AND, because classifiers cannot say OR. A dual-licensed package that only lists two classifiers will therefore look more restrictive than it is.
Transitive means "in the lockfile".
requirements.txtandgo.sumcarry no graph; every requirement is "direct" and Go direct-ness comes fromgo.modwhen present.Installed metadata is only used when its version equals the locked version; otherwise the note says so and the next source is tried. Environment markers mean a locked package may legitimately not be installed on your platform.
Unsupported: npm lockfile v1, pnpm before v6, Yarn Berry (v2+), Maven/Gradle/NuGet/Ruby/PHP.
Tests
pip install ".[test]" "ruff==0.16.0" "mypy==2.3.0"
ruff check src tests && mypy --strict src
pytest testsThe default run needs no network and no other tools. It uses lockfiles generated by the real tools
(uv lock, npm install --package-lock-only, pnpm install --lockfile-only; see
tests/fixtures/lock/README.md), hand-built site-packages / node_modules / cargo-registry trees, a
local HTTP server standing in for the registries, and a stdio test that launches the real server.
Two opt-in groups: pytest -m network (real PyPI, npm, crates.io) and pytest -m installs
(uses uv to install real packages into a temp venv).
There is also a from-scratch tutorial that builds a minimal version of this server step by step: license-mcp-the-hard-way.
License
MIT
Available Tools
6 toolscheck_policyARead-onlyIdempotent
Give each dependency a verdict - ok / needs review / violation - with reasons.
Policy comes from the arguments or from a .license-policy.toml in path (arguments win,
key by key). Entries in allow/deny are SPDX ids ('MIT', 'GPL-2.0' is read as GPL-2.0-only),
wildcards ('BSD-*'), or category names: public-domain, permissive, weak-copyleft,
strong-copyleft, network-copyleft, source-available, noncommercial, restricted, proprietary.
The TOML file may also hold project_license = "..." and an [exceptions] table mapping
a package name (or name@version) to the reason you accepted it.
Rules: deny beats allow; with an allow list, anything known and not on it is a violation;
otherwise, if project_license is given, each dependency is judged by the compatibility
table (compatible = ok, conditional = needs review, incompatible = violation); with
neither, permissive licenses are ok, weak copyleft (LGPL/MPL/EPL) needs review with linking
notes, and strong/network copyleft, source-available and non-commercial licenses are
violations. UNKNOWN and unclassified licenses always need review. OR expressions take the
best option for you, AND expressions the worst. Same license sources as license_inventory.
| Name | Required | Description | Default |
|---|---|---|---|
| deny | No | ||
| path | No | . | |
| allow | No | ||
| limit | No | ||
| online | No | ||
| python | No | ||
| show_ok | No | ||
| project_license | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the readOnly/idempotent annotations by disclosing the entire decision procedure: deny beats allow, allow-list makes unknown-on-list violations, project_license triggers the compatibility table, and the no-policy fallback treats permissive as ok and strong/network copyleft as violations. It also covers argument-vs-TOML precedence, exceptions, UNKNOWN handling, and OR/AND expression resolution. This is behavior an agent could not infer from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the verdict definition, then policy sources, then the rule ladder — a sensible order. The taxonomy lists (categories, license families) are long but each entry is load-bearing for the rules. The trailing 'Same license sources as license_inventory' is the only loose thread.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema and annotations cover the return shape and safety profile, and the policy semantics are thoroughly specified. The gap is the four undocumented inputs (limit, online, python, show_ok), which an agent cannot reason about from either the schema or the description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage the description must carry all eight parameters, and it does explain deny, allow, path, project_license and the TOML file lookup well. However, limit, online, python and show_ok are never mentioned, leaving half the surface undefined in both schema and prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a concrete verb and output shape: 'Give each dependency a verdict - ok / needs review / violation - with reasons.' That tells an agent exactly what resource is acted on and what comes back. It doesn't name the sibling it competes with (compatibility, which presumably judges a single pair), so sibling differentiation is implied rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the tool evaluates a whole project's dependencies against a policy, and 'Same license sources as license_inventory' hints at the relationship, but there is no explicit 'use this when, not that' guidance. Nothing tells the agent when to reach for compatibility or explain_license instead, and no preconditions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compatibilityARead-onlyIdempotent
Can code under dependency_license be used in a project licensed project_license?
Both accept SPDX ids/expressions or common spellings ('MIT', 'Apache 2', 'GPL-3.0-only', 'MIT OR Apache-2.0'); use 'proprietary' for a closed-source project. Answers compatible / conditional / incompatible / unknown from a small documented rule table (rule ids R1-R12 are cited), with the reasoning: e.g. Apache-2.0 into GPL-2.0-only is incompatible, into GPL-3.0 is fine; AGPL gets a network-clause note. A project offered under several licenses must be compatible with each option. Does not read any files.
| Name | Required | Description | Default |
|---|---|---|---|
| project_license | Yes | ||
| dependency_license | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered; the description adds real behavioral context instead of repeating it. It discloses the verdict taxonomy, that answers come from a small documented rule table with rule ids R1-R12 cited, that reasoning is included, and the AGPL network-clause caveat. It also states the non-obvious rule that a multi-licensed project must be compatible with every option.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core question is front-loaded and the following sentences each add distinct information: input formats, output vocabulary, rule provenance, and worked examples. It is dense but not padded; the parenthetical examples and the Apache-2.0/GPL illustration earn their space by disambiguating real edge cases. Slightly packed into one block rather than separated into structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter reasoning tool, the description covers input syntax, sentinel values, output categories, reasoning content, multi-license semantics, and the AGPL caveat, and it clarifies the tool accesses no files. With an output schema present it need not detail return structure, and nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% -- the schema offers only titles -- so the description carries the full burden and does so thoroughly. It specifies that both parameters accept SPDX ids or expressions as well as common spellings, gives concrete examples ('MIT', 'Apache 2', 'GPL-3.0-only', 'MIT OR Apache-2.0'), and introduces the 'proprietary' sentinel for closed-source projects, none of which is discoverable from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description frames the tool as a direct question -- can code under `dependency_license` be used in a project licensed `project_license` -- which is a specific, unambiguous verb/resource statement. It also names the four possible verdicts, so the agent knows exactly what comes back. It does not explicitly contrast itself with the sibling `check_policy`, which is the most likely source of confusion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is clear: this is a pure reasoning tool for the project-license vs dependency-license relationship, and 'Does not read any files' implicitly routes file-scanning tasks to siblings like `find_license_files` or `license_inventory`. It stops short of naming an alternative for policy evaluation (`check_policy`), so the boundary with that sibling is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_licenseARead-onlyIdempotent
Explain a license in plain words: what you can do, what you must do, and the limits.
Accepts an SPDX id ('MIT', 'GPL-3.0-only'), a common spelling ('Apache 2'), a deprecated id ('GPL-2.0' is read as GPL-2.0-only), or an expression ('MIT OR Apache-2.0', 'GPL-2.0-only WITH Classpath-exception-2.0'). Covers about 50 common licenses from an embedded, hand-written table; for others it says so rather than guessing. Does not read any files.
| Name | Required | Description | Default |
|---|---|---|---|
| spdx_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is a safe, idempotent read, and the description still adds real behavior: an embedded hand-written table of ~50 licenses, a hard coverage ceiling, and an explicit refusal to guess on unknown ids. The 'Does not read any files' note and the deprecated-id normalization rule ('GPL-2.0' read as 'GPL-2.0-only') are details an agent could not recover from annotations or schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence states what the tool produces, the second enumerates accepted input forms, and the third states the coverage limit and the no-file-access guarantee. No sentence is redundant, and the most decision-relevant content leads.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter lookup tool with an output schema, nothing essential is missing: input formats, coverage bounds, and the out-of-scope behavior are all stated. Return-value details are correctly left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden for the single spdx_id parameter, and it does: it lists accepted forms (SPDX id, common spelling like 'Apache 2', deprecated id, and compound expressions with OR/WITH) with concrete examples. This is meaning well beyond the bare untyped string the schema exposes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Explain a license') and enumerates the shape of the answer ('what you can do, what you must do, and the limits'). It also explicitly excludes a neighboring capability with 'Does not read any files', which separates it from find_license_files and license_inventory without requiring either schema to be opened.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is framed clearly: reach for it when you have a license identifier or expression and want a plain-language reading, and it states the failure condition ('for others it says so rather than guessing'). It does not, however, say when to prefer compatibility or check_policy over this tool, so the agent must infer the boundary itself.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_license_filesARead-onlyIdempotent
Show which dependencies ship a LICENSE / COPYING / NOTICE file in their installed copy.
Looks in the project's venv dist-info (including PEP 639 licenses/), node_modules package
directories and ~/.cargo/registry. Lists packages with files (flagging NOTICE files you must
reproduce under Apache-2.0), packages installed without any license file, and packages with no
installed copy to inspect. Offline only.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | . | |
| python | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds real value beyond that: it enumerates the three result buckets (packages with files, installed without a license file, no installed copy to inspect), calls out NOTICE files that must be reproduced under Apache-2.0, and states the offline constraint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose is front-loaded in the first sentence, with the scan locations and result categories following in support. Formatting with line breaks reads well; wording is efficient with little filler, though the parenthetical about Apache-2.0 could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be spelled out, and the description still sketches the three result categories and the NOTICE caveat. Combined with the annotation-declared safety profile, this is nearly complete; only the parameter semantics are missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and neither parameter is documented in the schema. The description references 'the project' implicitly mapping to `path`, but never explains `path` semantics or what the `python` parameter selects (interpreter? venv target?). With two undocumented parameters and no compensating meaning, this is a clear gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Show which dependencies ship a LICENSE / COPYING / NOTICE file in their installed copy,' and names the exact ecosystems scanned (venv dist-info incl. PEP 639 `licenses/`, node_modules, ~/.cargo/registry). It is clearly distinct from a sibling like generate_notices, but it never explicitly contrasts itself with license_inventory, which sounds adjacent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the reader infers this is the tool to reach for when auditing on-disk license files offline. 'Offline only' is useful scoping, but there is no explicit when-to-use guidance nor a pointer to license_inventory or generate_notices as alternatives, so the agent must guess at routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_noticesARead-onlyIdempotent
Draft a THIRD-PARTY-NOTICES.md for the project's dependencies, returned as text (nothing is written).
One entry per package: name, version, license, where the license came from, and copyright lines found in the package's installed LICENSE/COPYING files (or 'not found'). Packages with an UNKNOWN license are grouped under a heading so they cannot be missed. License texts are not embedded - copy them from the packages' own files (see find_license_files). Same license sources as license_inventory; copyright lines only exist for packages that are installed.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | . | |
| online | No | ||
| python | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare read-only, non-destructive, idempotent, and open-world behavior. The description adds important operational detail: output is text only, UNKNOWN licenses are grouped prominently, license texts are not embedded, and copyright lines exist only for installed packages.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and output artifact, then adds only relevant constraints and cross-references. Sentences are dense but purposeful, with no obvious filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description need not explain return structure, and it does cover output content and key caveats well. However, for a tool with three inputs and 0% schema description coverage, the complete absence of parameter guidance is a meaningful gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for three parameters, and the description never mentions path, online, or python. Contextual wording about the project and installed packages loosely hints at path or interpreter context, but the inputs remain essentially unexplained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and artifact: draft a THIRD-PARTY-NOTICES.md for project dependencies, returned as text with nothing written. It distinguishes the tool from license_inventory by outputting notices and from find_license_files by explicitly not embedding license texts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context: generate notice text, use find_license_files to copy license texts, and note that license sources match license_inventory. It stops short of explicit when-not guidance or direct selection advice versus check_policy and compatibility.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
license_inventoryARead-onlyIdempotent
List every dependency's license, grouped, with where each answer came from.
path is a project directory (lockfiles are found up to 3 levels down) or one lockfile.
License sources, in priority order: (1) packages already installed - a Python venv at
.venv/venv next to the lockfile, or the one you give as python (a venv dir, its
python executable, or a site-packages dir), node_modules, ~/.cargo/registry; (2) data in
the lockfile itself (package-lock.json has it); (3) a network lookup against PyPI / npm /
crates.io, ONLY if online=true. Anything none of these answers is UNKNOWN - never guessed.
The output groups packages by normalised SPDX expression with direct/transitive counts,
lists UNKNOWN packages with the reason, shows dual-licensed (OR) packages and which option
applies (allow is an optional list of SPDX ids you accept; otherwise the least
restrictive option is shown), and flags ambiguous spellings such as plain 'BSD'.
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | . | |
| allow | No | ||
| online | No | ||
| python | No | ||
| list_limit | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover read-only/idempotent safety, but the description adds the behavior that actually matters for trust: a strict source priority ladder, no network access unless online=true, and a hard 'never guessed' rule that routes unresolved cases to UNKNOWN with a reason. It also previews how ambiguity (dual-licensed OR, plain 'BSD') is surfaced rather than silently resolved.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then organized into source priority, output shape, and licensing edge cases. It is dense with nested parentheticals (the 'python' parameter alone packs three forms into one clause), which slows parsing slightly, but no sentence is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still usefully frames what the report contains: grouped SPDX expressions, direct/transitive counts, UNKNOWN reasons, dual-license options. Combined with named license sources and the offline-by-default rule, an agent can call this confidently; the sole gap is the undocumented list_limit parameter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and mostly does: 'path' scoping and search depth, 'python' accepted forms (venv dir, python executable, or site-packages dir), 'online' as the network gate, and 'allow' as an optional SPDX allow-list controlling which OR option is reported. Only 'list_limit' is left completely unexplained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource: 'List every dependency's license, grouped, with where each answer came from.' The provenance angle plus grouping distinguishes it from siblings like check_policy (policy evaluation) and generate_notices (artifact generation) without needing schema inspection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context: 'path' can be a project dir or a single lockfile, lockfiles are searched 3 levels down, and network lookup only happens when online=true. It never explicitly names an alternative or says when-not to use it versus check_policy or compatibility, so it stops short of full when/when-not guidance.
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.
6 tool updates
v0.1.0- First observed
check_policy - First observed
compatibility - First observed
explain_license - First observed
find_license_files - First observed
generate_notices - First observed
license_inventory
TDQS
Scored across 6 tools
Each tool targets a clearly distinct task: inventory listing, policy verdicts, pairwise license compatibility, plain-language explanations, notice generation, and license-file discovery. The descriptions explicitly clarify boundaries, such as compatibility not reading files and check_policy applying a project policy. An agent should have no trouble selecting the right tool.
All tool names use consistent snake_case and are readable. Most follow a verb_noun pattern (check_policy, explain_license, generate_notices, find_license_files), while license_inventory is noun_noun and compatibility is a bare noun. Minor deviations only.
Six tools is well-scoped for a license-compliance server. Each tool covers a distinct part of the workflow and none appears redundant or like padding.
The surface covers the core license-compliance lifecycle: discover licenses, check project policy, assess pairwise compatibility, explain licenses, generate third-party notices, and locate license files. No obvious critical gaps remain for the stated purpose.
Maintenance
Related MCP Connectors
Open-source licence risk checks for AI coding agents and dependency trees.
Generate, audit, and maintain legal policies that match what your code actually does.
Trust-check any dependency for agents: OpenSSF Scorecard, licenses, CVEs, deps. 7 ecosystems.
CVE lookups (NVD) and dependency-manifest audits (OSV) for AI agents. No API keys.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables scanning of project dependencies across multiple package managers (npm, pip, cargo, etc.) and generates comprehensive markdown license reports. Supports automatic license detection from package registries with caching for improved performance.-
- AlicenseAqualityBmaintenanceEnables AI coding agents to audit Python and npm dependency licenses against your distribution context before shipping, returning CLEAN, REVIEW, or BLOCK verdicts with plain-language reasons and supporting notice generation.31MIT
- AlicenseAqualityCmaintenanceProvides authoritative open source license answers: SPDX identification, copyleft classification, and compatibility checks of dependencies against your project's license.31MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI coding agents to scan a project's real dependency tree against a declared shipping intent (e.g. hosted closed-source SaaS) and return contextual license alerts with package paths, rule IDs, and assumptions. Also explains the highest-priority findings, shows resolved license evidence, and updates the shipping intent before rescanning.1MIT