Skip to main content
Glama
jedi-knights

jk-mcp-mls

by jedi-knights

jk-mcp-mls

MCP server that gives Claude live access to Major League Soccer data — teams, matches, standings, rosters, and schedule-strength analytics — via the ESPN public API.

CI Badge Coverage Evals Release Python License: MIT


Table of Contents


Related MCP server: sports-pulse-mcp

Overview

AI assistants like Claude are knowledgeable, but they have a hard cutoff date — they cannot tell you today's MLS standings, last night's scores, or which teams are currently in a playoff position. This project fixes that.

It is an MCP server — a plugin that gives Claude direct access to live MLS data: scores, standings, rosters, and derived schedule-strength analytics. Once installed, you can ask Claude natural-language questions about Major League Soccer and get accurate, up-to-date answers. No subscription, no API key, and no programming required to use it.

This is the v1 scaffold — it wraps the ESPN public API only. Richer sources (mlssoccer.com's Opta-powered feed, official CMS award articles, Leagues Cup, U.S. Open Cup, Concacaf Champions Cup) are on the roadmap.


Features

The v1 surface is eleven read-only, idempotent tools split across two tiers.

ESPN-backed (8)

Tool

Description

get_teams

List all 30 MLS clubs with IDs and abbreviations

get_team

Details for a specific team

get_roster

Team's active roster — jersey, position, age, citizenship

get_scoreboard

Match scores for a single day, a date range, or the current matchweek

get_team_schedule

Every match for a team in the current season — past + upcoming

get_match_details

One match's full details — score, venue, attendance, goals, cards, subs

get_standings

Current standings grouped by Eastern and Western Conferences

get_news

Recent MLS news articles

Derived analytics (3)

Pure functions over live standings + team schedules, exposing schedule-strength context the raw table does not.

Tool

Description

get_strength_of_schedule

Team's average opponent points-per-game across matches already played

get_results_by_opponent_tier

Team's W-L-T split across current top / middle / bottom standings tiers

get_adjusted_points_per_game

Team's raw PPG alongside an opponent-quality-adjusted PPG

Roadmap

Not in v1; probed and shown to be viable at the ESPN API:

  • Leagues Cup (concacaf.leagues.cup), U.S. Open Cup (usa.open), Concacaf Champions Cup, Campeones Cup

  • Player leaderboards and team season aggregates once a stable MLS Opta feed is identified

  • Award articles via mlssoccer.com CMS

  • Playoff bracket for the MLS Cup Playoffs


Requirements


Installation

git clone https://github.com/jedi-knights/jk-mcp-mls.git
cd jk-mcp-mls
uv sync

Usage

Run the server in stdio mode (the default — used by Claude Code and Claude Desktop):

uv run python -m mls.server

Run in HTTP mode (for networked or deployed access):

MCP_TRANSPORT=streamable-http uv run python -m mls.server

Example prompts

Standings, scores, rosters:

  • Who is leading the MLS Eastern Conference right now?

  • Show me every MLS result from this past weekend.

  • Who is on Atlanta United's roster?

  • When does LAFC play next?

Schedule strength:

  • Which MLS team has played the toughest schedule so far?

  • Show me Atlanta United's record against the current top 5 teams.

  • Compare Inter Miami and Seattle Sounders on adjusted points-per-game.


Configuration

All configuration is via environment variables. None are required for local use.

Variable

Default

Description

MCP_TRANSPORT

stdio

Transport mode: stdio or streamable-http

HOST

0.0.0.0

Bind address (HTTP transport only)

PORT

8000

TCP port (HTTP transport only)

MCP_PATH

/mcp/mls

URL path (HTTP transport only)

API_HOST

https://site.api.espn.com

ESPN API base URL

LOG_LEVEL

INFO

DEBUG, INFO, WARNING, or ERROR

MCP_TRACING_ENABLED

unset

Bootstrap the OpenTelemetry SDK

MCP_AUTH_ENABLED

unset

Require RS256 bearer tokens on streamable-http

MCP_AUTH_ISSUER_URL

unset

Auth-server origin (required when auth is on)

MCP_AUTH_RESOURCE_URL

unset

This server's public URL for the aud claim


Claude Code

Install from your local clone globally so the server is available in every project:

claude mcp add --scope user mls -- uv run --directory /path/to/jk-mcp-mls python -m mls.server

Replace /path/to/jk-mcp-mls with the absolute path to your clone. Verify with claude mcp list.

Drop --scope user to register only for the current project, or commit a .mcp.json to the repo root for collaborators:

{
  "mcpServers": {
    "mls": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/jk-mcp-mls", "python", "-m", "mls.server"]
    }
  }
}

Claude Desktop

Add the following to your Claude Desktop configuration file.

Location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "mls": {
      "command": "uv",
      "args": [
        "run",
        "--directory", "/path/to/jk-mcp-mls",
        "python", "-m", "mls.server"
      ]
    }
  }
}

If uv is not on Claude Desktop's PATH, use the absolute path (which uv will show it). Fully quit and relaunch Claude Desktop after saving — a window close is not enough.


Docker

Build the image:

docker build -t jk-mcp-mls:latest .

Run in stdio mode (for MCP clients that spawn a subprocess):

docker run -i --rm jk-mcp-mls:latest

Run in HTTP mode:

docker run --rm -p 8000:8000 \
  -e MCP_TRANSPORT=streamable-http \
  jk-mcp-mls:latest

Development

Install

uv sync

Invoke tasks

All common workflows are invoke tasks. Run uv run inv --list to see everything.

Task

Alias

Description

uv run inv lint

inv l

Run ruff linter and format check

uv run inv lint --fix

inv l --fix

Auto-fix lint violations and reformat

uv run inv test

inv t

Run the full test suite

uv run inv coverage

inv v

Run tests with coverage report (threshold: 90%)

uv run inv check-complexity

inv cc

Check cyclomatic complexity (max 7)

uv run inv build

inv b

Build wheel and sdist into dist/

uv run inv build-image

inv bi

Build the Docker image

uv run inv clean

inv c

Remove build and coverage artifacts

Project structure

src/mls/
├── server.py                     # entry point, transport selection, logging setup
├── adapters/
│   ├── inbound/
│   │   ├── mcp_adapter.py        # FastMCP server, health endpoints, tool registration
│   │   ├── formatters.py         # domain → LLM-readable text
│   │   ├── authorization.py      # inbound authz port implementations
│   │   └── tools/
│   │       ├── espn.py           # 8 ESPN-backed tools
│   │       └── analytics.py      # 3 schedule-strength analytics tools
│   └── outbound/
│       ├── espn_adapter.py       # ESPN HTTP client
│       ├── parsers.py            # ESPN JSON → domain models
│       ├── retry_adapter.py      # transient-failure retry decorator
│       └── caching_adapter.py    # in-process TTL cache
├── application/
│   ├── service.py                # MLSService — use cases, orchestration
│   ├── _helpers.py               # input validation
│   └── _analytics_helpers.py     # pure math for schedule-strength tools
├── domain/
│   ├── models.py                 # Team, Match, Standing (with conference), etc.
│   └── exceptions.py             # MLSNotFoundError, UpstreamAPIError
├── ports/
│   ├── inbound.py                # Authorizer protocol
│   └── outbound.py               # MLSAPIPort protocol
├── observability/                # OpenTelemetry bootstrap (opt-in)
└── security/                     # JWKS token verifier

The dependency direction flows inward: adapters → ports → domain. Nothing in domain/ imports from adapters or a framework.


Contributing

  1. Fork the repository and clone your fork

  2. Create a feature branch: git checkout -b feature/your-feature

  3. Make your changes following the existing patterns (hexagonal architecture, TDD, conventional commits)

  4. Verify the full check suite passes: uv run inv lint && uv run inv check-complexity && uv run inv coverage

  5. Open a pull request against main

All CI checks (lint, complexity, tests, coverage ≥ 90%) must pass before merge.


License

MIT — see LICENSE.

Available Tools

11 tools
get_adjusted_points_per_gameA
Read-onlyIdempotent

Get a team's raw points-per-game alongside an opponent-quality-adjusted PPG.

Adjusted PPG scales raw PPG by avg_opponent_ppg / league_average_ppg, so values above raw PPG indicate the team has earned points against a tougher schedule than league average.

Args: team_id: ESPN numeric team ID.

ParametersJSON Schema
NameRequiredDescriptionDefault
team_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnly=True, destructive=False, and idempotent=True, so the safety profile is clear. The description adds behavioral context by explaining the adjustment formula (avg_opponent_ppg / league_average_ppg) and how to interpret values relative to raw PPG. This goes beyond what annotations provide and helps the agent reason about the computation.

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 front-loaded with the main purpose, followed by a compact formula explanation and an arguments line. Every sentence adds value, and the structure is clean. The 'Args' block is redundant with the schema but serves as a useful inline reminder given that the schema lacks descriptions.

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?

The description explains what the tool returns (raw and adjusted PPG) and the reasoning behind the adjustment. With an output schema present, return values do not need to be spelled out. It does not cover error conditions or rate limits, but for a simple read-only tool this is adequate. The description is complete enough for an agent to invoke it correctly.

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 input schema only defines team_id as a string with no description (0% coverage). The description compensates by stating 'team_id: ESPN numeric team ID', which clarifies the expected format and meaning. This is sufficient for the single parameter, though it could also mention that the team must exist in ESPN systems.

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 uses a specific verb+resource ('Get a team's raw points-per-game alongside an opponent-quality-adjusted PPG') and clearly distinguishes this from sibling tools like get_standings or get_strength_of_schedule. It names the exact metric and includes a concise definition.

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

Usage Guidelines4/5

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

The description implies the primary use case: retrieving a team's PPG with an adjustment for opponent quality. It does not explicitly discuss exclusions or alternatives, but the formula explanation gives context for when this metric is relevant. A clear alternative comparison is missing, so it does not fully reach a 5.

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

get_match_detailsA
Read-onlyIdempotent

Get detailed information for a single MLS match.

Returns the score, venue, attendance, and a chronological list of key events (goals, substitutions, cards). Use the match ID returned by get_scoreboard or get_team_schedule.

Args: match_id: ESPN numeric event ID (e.g. "401853883").

ParametersJSON Schema
NameRequiredDescriptionDefault
match_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint false). The description adds useful behavioral context by specifying the response includes score, venue, attendance, and a chronological list of key events. No contradiction with annotations.

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

Conciseness5/5

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

The description is appropriately sized and front-loaded: purpose, return payload, usage, and parameter details in a compact structure. Every sentence earns its place with no filler or redundant restating of the schema.

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

Completeness5/5

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

With one parameter, clear parameter semantics, and an output schema present, the description provides complete contextual coverage. It covers what the tool does, what it returns, and how to obtain the required ID, while annotations handle the safety profile.

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

Parameters5/5

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

Schema coverage is 0%, but the description fully compensates by explaining that match_id is an ESPN numeric event ID and providing a concrete example. It also tells the agent where to obtain the ID, which is exactly what is needed to populate the sole parameter correctly.

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 opens with 'Get detailed information for a single MLS match', which is a specific verb+resource statement. It immediately lists returned fields (score, venue, attendance, key events), clearly distinguishing it from sibling listing tools like get_scoreboard and get_team_schedule.

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

Usage Guidelines4/5

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

Explicitly instructs to use the match ID returned by get_scoreboard or get_team_schedule, giving clear context for when to invoke this tool. It does not state explicit exclusions, so it falls short of a 5, but the guidance is actionable and helpful.

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

get_newsA
Read-onlyIdempotent

Get recent MLS news articles.

Returns each article's headline, publication date, summary, and link to the full ESPN story.

Args: limit: Maximum number of articles to return (default 10).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already establish that this is a read-only, idempotent, non-destructive operation, so the description does not need to restate that. The description adds value by disclosing the return structure (headline, publication date, summary, link to ESPN) and the default limit, which goes beyond the schema. However, it does not mention any potential variability, such as the number of articles when 'recent' is ambiguous or possible downtime, but these are minor given the scope.

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 concise and well-structured. It opens with a clear purpose statement, follows with the return details, and ends with a parameter explanation. Each sentence earns its place without redundant filler. The use of an 'Args:' section makes the parameter documentation easy to scan.

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

Completeness5/5

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

The tool is simple with one optional parameter and an output schema, and the description covers the purpose, return fields, and parameter semantics. Annotations provide the safety and idempotency profile. No further details like authentication or rate limits are necessary for a read-only news-fetching tool, making the description complete for the tool's complexity.

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

Parameters5/5

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 explaining parameters. The description provides clear semantics: 'limit: Maximum number of articles to return (default 10).' This explains both the purpose of the parameter and its default value, which is not available in the schema beyond the default attribute. The explanation is precise and sufficient for a single parameter.

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

Purpose5/5

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

The description clearly states the verb and resource: 'Get recent MLS news articles.' This distinguishes it from sibling tools that focus on teams, scores, rosters, schedules, and standings, as news articles are a distinct resource. The specificity of 'recent MLS news' leaves no ambiguity about what the tool returns.

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 the tool should be used when a user wants recent MLS news, but it does not explicitly state when to use this tool versus alternatives or mention any exclusions. While the sibling tools are clearly different in topic, there is no direct guidance such as 'for scores, use get_scoreboard' or 'when you need news, use get_news.' The usage context is inferred rather than explicitly provided.

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

get_results_by_opponent_tierA
Read-onlyIdempotent

Get a team's W-L-T splits against current top-tier, middle, and bottom-tier teams.

Tiers are derived from the live league standings: top tier_size, bottom tier_size, and everyone in between. Lets you ask "how does this team do against the top of the table?" without scanning every result manually.

Args: team_id: ESPN numeric team ID. tier_size: Number of teams in each of the top and bottom tiers. Defaults to 5. Must be at least 1, and 2*tier_size must not exceed the league size.

ParametersJSON Schema
NameRequiredDescriptionDefault
team_idYes
tier_sizeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds valuable behavioral detail: tiers are derived from live league standings, and tier_size has constraints (minimum 1, 2*tier_size <= league size). This goes beyond the annotations and helps the agent understand how the tool behaves at runtime.

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 concise and well-structured. The first sentence states the purpose, followed by a brief explanation of tier derivation, a use-case rationale, and an Args section. Every sentence contributes unique information; there is no redundancy or verbosity.

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

Completeness5/5

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

Given only 2 parameters, an output schema, and clear annotations, the description fully covers the tool's behavior. It explains the tier logic, constraints, and provides a comparison to manual scanning, which together give an agent complete context for selection and invocation.

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

Parameters5/5

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

With 0% schema description coverage, the description must fully explain parameters. It does: team_id is identified as an ESPN numeric team ID, and tier_size is explained with its default value and validation constraints. This adds rich meaning beyond the bare schema property names.

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 opens with a specific verb and resource: 'Get a team's W-L-T splits against current top-tier, middle, and bottom-tier teams.' This clearly states what the tool does and uniquely distinguishes it from sibling tools like get_standings or get_team_schedule by focusing on opponent-tier splits. The purpose is precise and not tautological.

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

Usage Guidelines4/5

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

The description provides a clear contextual use case: 'Lets you ask "how does this team do against the top of the table?" without scanning every result manually.' This implies when to use the tool, but it does not explicitly name alternative tools or state when not to use it. Because it gives meaningful usage context without exclusions, it earns a 4.

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

get_rosterA
Read-onlyIdempotent

Get the active roster for an MLS team.

Returns each player's jersey number, name, position, citizenship, and age. Use the team ID returned by get_teams.

Args: team_id: ESPN numeric team ID (e.g. "18418" for Atlanta United FC).

ParametersJSON Schema
NameRequiredDescriptionDefault
team_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the agent understands it's a safe read. The description adds the 'active roster' scoping detail and the source of team_id, which is useful behavioral context beyond the annotations.

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

Conciseness5/5

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

The description is compact and front-loaded with the main purpose. It includes a minimal Args section with no redundant information; every sentence earns its place.

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

Completeness5/5

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

For a simple read-only tool with one parameter, clear annotations, and an output schema, the description covers purpose, usage, and parameter semantics sufficiently. It leaves no critical gaps for selection or invocation.

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

Parameters5/5

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

The input schema provides no description for team_id, so the description must compensate. It clearly explains the parameter as an ESPN numeric team ID, gives a concrete example, and directs users to get_teams for the correct value—fully covering the parameter semantics.

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 opening 'Get the active roster for an MLS team' is a clear verb+resource statement. It doesn't explicitly distinguish from sibling get_team, but 'roster' is specific enough and the mention of get_teams provides context.

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

Usage Guidelines4/5

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

The description explicitly instructs to use the team ID returned by get_teams, establishing a clear prerequisite and workflow. It doesn't discuss when not to use it, but the context implies this is the roster-specific tool.

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

get_scoreboardA
Read-onlyIdempotent

Get MLS match scores and status for a date or date range.

With no arguments, returns matches for the current matchweek. With date only, returns matches for that single day. With both date and end_date, returns every match in the inclusive range.

Args: date: Optional start date in YYYYMMDD format (e.g. "20260418"). end_date: Optional end date in YYYYMMDD format. Requires date.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateNo
end_dateNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, which cover the safety profile. The description adds meaningful behavioral context beyond annotations, such as the 'current matchweek' default behavior, the inclusive range semantics, and the requirement that end_date depends on date. No contradictions exist.

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 concise and well-structured: a one-sentence summary followed by bullet-like argument behavior and an Args list. Every sentence adds value, with no repetition of schema details or fluff.

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

Completeness5/5

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

All argument behaviors and constraints are fully documented, including the default case, date-only case, and date-range case. An output schema exists, so return-value details are not required. The tool is simple and the description covers all necessary usage context.

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

Parameters5/5

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. It explicitly defines each parameter, including the YYYYMMDD format and the dependency of end_date on date. This fully compensates for the absence of schema 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 opens with a specific verb and resource: 'Get MLS match scores and status for a date or date range.' It further clarifies behavior based on arguments (no args, date only, date+end_date), which clearly distinguishes it from siblings like get_match_details or get_team_schedule.

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

Usage Guidelines4/5

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

The description gives clear context for when to use each argument combination: no arguments returns the current matchweek, date returns a single day, and both date and end_date provide an inclusive range. It does not explicitly name alternative tools or exclusions, so it falls short of a 5.

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

get_standingsA
Read-onlyIdempotent

Get the current MLS standings, grouped by conference.

MLS is split into Eastern and Western Conferences (15 teams each in the current alignment). The response renders each conference as a separate numbered table ordered by points descending, with win/loss/tie record, goals for, goals against, and goal differential.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already indicate read-only, idempotent, open world, and non-destructive. The description adds valuable behavioral detail beyond annotations: the response format (separate numbered tables per conference), ordering (points descending), and included stats (W/L/T, goals for/against, differential). This provides transparency about output structure without contradicting annotations.

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

Conciseness5/5

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

The description is concise and front-loaded with the core purpose, followed by a brief, useful elaboration on the response format. Every sentence adds value; no wasted words.

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

Completeness5/5

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

The tool is simple with no parameters, and the description fully explains what the output will contain. It provides enough context for an agent to select this tool and understand the response, even without the output schema being shown.

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 schema coverage is trivially 100%. The description doesn't need to explain parameters. Baseline for 0 params is 4.

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

Purpose5/5

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

The description clearly states the tool's function: 'Get the current MLS standings, grouped by conference.' It specifies the resource (MLS standings) and the organization (conference). It distinguishes from sibling tools like get_teams and get_scoreboard by focusing on standings.

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

Usage Guidelines4/5

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

The description implies usage context: use when you need current standings with conference breakdown. It doesn't explicitly name alternatives, but the context is clear enough given the sibling tools. A slightly higher score is not warranted because it doesn't say 'use instead of X'.

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

get_strength_of_scheduleA
Read-onlyIdempotent

Get a team's strength of schedule based on opponents already faced.

Returns the average current points-per-game of every opponent the team has played in completed matches, plus a per-opponent breakdown. Useful early in the season for "who has played the tougher schedule so far?" questions.

Args: team_id: ESPN numeric team ID (e.g. "18418" for Atlanta United FC).

ParametersJSON Schema
NameRequiredDescriptionDefault
team_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false. The description adds behavioral context by specifying it computes average points-per-game of opponents in completed matches and returns a per-opponent breakdown, going beyond what annotations provide.

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 concise and front-loaded with the core purpose, followed by return details and a use case. It avoids fluff and includes only valuable information, with the Args section providing a clear parameter explanation.

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

Completeness5/5

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

For a single-parameter, read-only tool with a full output schema and rich annotations, the description is complete. It covers purpose, scope, parameter format, and suggests when to use it, leaving no significant gaps.

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

Parameters5/5

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

Schema coverage is 0%, but the description fully compensates by explaining team_id as an 'ESPN numeric team ID' with a concrete example ('18418' for Atlanta United FC). This gives the agent all necessary context to supply the parameter correctly.

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

Purpose5/5

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

The description clearly states a specific verb and resource: 'Get a team's strength of schedule based on opponents already faced.' It further defines the output as average points-per-game plus a per-opponent breakdown, distinguishing it from sibling tools like get_standings or get_team_schedule.

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

Usage Guidelines4/5

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

The description gives explicit usage context: 'Useful early in the season for "who has played the tougher schedule so far?" questions.' It does not mention exclusions or alternatives explicitly, but the context is clear enough for selection.

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

get_teamA
Read-onlyIdempotent

Get details for a specific MLS team.

Returns full team information including display name, abbreviation, and location. Use the numeric ID returned by get_teams.

Args: team_id: ESPN numeric team ID (e.g. "18418" for Atlanta United FC).

ParametersJSON Schema
NameRequiredDescriptionDefault
team_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, covering the safety profile. The description adds context about returns ('full team information including display name, abbreviation, and location') but does not disclose error behavior or rate limits. This is comparable to the reference example for a read-only tool.

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 short, front-loaded with the purpose, and contains no filler. The Args block clearly documents the parameter format and origin.

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

Completeness5/5

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

For a simple single-parameter read-only tool with an output schema and rich annotations, the description fully covers the necessary context: what it does, how to obtain the input, and what it returns. No gaps remain.

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

Parameters5/5

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

While the schema only says 'Team Id', the description explains it is an ESPN numeric team ID, gives an example, and specifies that it comes from get_teams. This fully compensates for the 0% schema coverage.

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 uses a specific verb and resource ('Get details for a specific MLS team'), and distinguishes itself from the sibling get_teams by emphasizing 'specific' and referencing the numeric ID. The return content is also previewed.

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

Usage Guidelines5/5

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

It explicitly states to use the numeric ID returned by get_teams, which both names the sibling tool and establishes a prerequisite. This makes the appropriate usage context clear.

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

get_teamsA
Read-onlyIdempotent

Get all active MLS teams.

Returns a numbered list of teams with their ID, full name, abbreviation, and home city. Use the ID or abbreviation with get_team to retrieve detailed information about a specific team.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering safety. Description adds 'active' and return fields (numbered list with ID, name, abbreviation, city), which is useful context beyond the structured metadata. It doesn't mention ordering or pagination, but the output schema covers return structure.

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?

Three sentences, each earning its place: purpose, returned fields, and follow-up usage. Front-loaded with the primary action and immediately actionable.

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

Completeness5/5

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

For a zero-parameter list endpoint with a rich output schema and strong annotations, the description provides purpose, output contents, and a pointer to the relevant sibling. Nothing important is missing for an agent to invoke it correctly.

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 schema coverage is trivially 100%. Baseline for 0 params is 4; the description correctly omits parameter details since none exist.

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 opens with 'Get all active MLS teams' – a specific verb, resource, and scope. It distinguishes from sibling get_team by noting that detailed specific-team information is available via get_team. Clearly states what output includes (ID, name, abbreviation, city).

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

Usage Guidelines5/5

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

States the use case: retrieving all active teams. Explicitly directs the agent to use get_team with the ID or abbreviation for detailed information, providing a clear alternative for a common follow-up. No exclusions needed for a zero-parameter list tool.

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

get_team_scheduleA
Read-onlyIdempotent

Get all matches for a single MLS team in the current season.

Returns scheduled, in-progress, and completed matches for the team — with opponent, date, score (if played), and status.

Args: team_id: ESPN numeric team ID (e.g. "18418" for Atlanta United FC).

ParametersJSON Schema
NameRequiredDescriptionDefault
team_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and non-destructive behavior. The description adds meaningful behavioral context by detailing the return fields (opponent, date, score if played, status) and the scope (current season, all matches). This goes beyond the annotations, though it stops short of describing pagination or possible edge cases like cancelations.

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 concise and front-loaded: the first sentence states the purpose, the second summarizes the response content, and the Args line gives parameter semantics. No sentence is wasted, and the structure is easy to scan.

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

Completeness5/5

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

Given the tool's simplicity (one parameter, output schema present, clear annotations), the description is complete. It covers what the tool returns, which team it applies to, and how to specify the team. There is no notable gap for an agent to correctly select and invoke the tool.

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

Parameters5/5

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

The input schema only provides 'team_id' as a required string with no description, leaving 0% schema coverage. The description compensates fully by explaining that it expects an ESPN numeric team ID and provides a concrete example ('18418' for Atlanta United FC). This gives the agent exact guidance for supplying the parameter.

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 opens with a specific verb and resource: 'Get all matches for a single MLS team in the current season.' This clearly identifies both the action and the scope, differentiating it from siblings like get_match_details (single match) and get_scoreboard (general scoreboard). It also enumerates what is included (scheduled, in-progress, completed) without ambiguity.

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

Usage Guidelines4/5

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

The description clearly states when to use the tool: when you need all matches for one MLS team in the current season. It does not explicitly mention alternatives or exclusions, but the context of sibling tools and the tool's name make the intended use obvious. A score of 5 would require explicit 'use this instead of X' guidance, which is absent.

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. 11 tool updatesv0.1.0
    • First observedget_adjusted_points_per_game
    • First observedget_match_details
    • First observedget_news
    • First observedget_results_by_opponent_tier
    • First observedget_roster
    • First observedget_scoreboard
    • First observedget_standings
    • First observedget_strength_of_schedule
    • First observedget_team
    • First observedget_team_schedule
    • First observedget_teams

TDQS

A4.6/5.0

Scored across 11 tools

Disambiguation4/5

Most tools are clearly distinct (teams, roster, scoreboard, standings, news), but the three team-performance analytics tools (strength_of_schedule, results_by_opponent_tier, adjusted_points_per_game) share a similar shape and could be confused if an agent doesn't read the descriptions carefully.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: 'get_' followed by a specific resource (teams, team, scoreboard, roster, etc.). There is no mixing of conventions or vague verbs.

Tool Count5/5

11 tools is well within the ideal 3-15 range for a domain-specific server. Each tool covers a distinct need, and the count feels appropriately scoped without being excessive or too thin.

Completeness5/5

The server provides comprehensive read-only coverage for MLS data: team info, rosters, matches (by date and by team), standings, news, and advanced performance metrics. There are no obvious dead ends or missing core operations for a read-only informational server.

Maintenance

ActivityNo data
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that connects Claude Desktop to The Odds API, giving Claude real-time access to sports odds, scores, and schedules across 80+ sports and leagues worldwide.
    -
  • F
    license
    B
    quality
    D
    maintenance
    MCP server that enables Claude Desktop to access real-time sports data including live scores, fixtures, standings, and NBA statistics using free APIs.
    10
    -
  • A
    license
    A
    quality
    B
    maintenance
    MCP server providing Claude live access to USL Super League data—teams, matches, standings, rosters, and schedule-strength analytics—via the ESPN public API.
    11
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    MCP server that gives Claude live access to Women's Super League (England) data — teams, matches, standings, rosters, and schedule-strength analytics — via the ESPN public API.
    11
    MIT