Codeward integrates with the Model Context Protocol in two complementary ways:
- Codeward as an MCP server — exposes GitLab-aware tools, resources, and prompts to any MCP client (Claude Desktop, Cursor, an Agno agent in another project, ...).
- Codeward as an MCP client — agents can call tools from any
external MCP server you declare in
codeward.yml.
This page covers both directions.
Codeward mounts a FastMCP server
at /mcp. The mount is wired up in codeward/main.py and the server
itself is built in codeward/mcp_server/server.py.
- URL:
http://<host>:8420/mcp - Transport: streamable HTTP (FastMCP
streamable_http_app) - Auth: optional bearer token via
CODEWARD_MCP_KEY - Source:
codeward/mcp_server/{server,tools,resources,prompts}.py
Set CODEWARD_MCP_KEY in .env to require a bearer token on every
request to /mcp:
CODEWARD_MCP_KEY=replace-with-a-long-random-stringWhen the key is set, MCPAuthMiddleware rejects requests whose
Authorization header is missing or does not match
Bearer <CODEWARD_MCP_KEY>. If CODEWARD_MCP_KEY is unset, the mount
is exposed without authentication — useful for local development, but
not recommended for any deployment that GitLab can reach over a
non-trusted network.
Registered in codeward/mcp_server/tools.py:
| Tool | Purpose |
|---|---|
list_merge_requests(project, state, max_results) |
List MRs in a given state |
get_merge_request(project, mr_iid) |
Fetch a single MR's metadata |
get_merge_request_diff(project, mr_iid) |
Fetch the changes for a single MR |
post_merge_request_comment(project, mr_iid, body) |
Post a note on an MR |
list_issues(project, ...) |
List issues with filters |
get_issue(project, issue_iid) |
Fetch a single issue |
create_issue(project, ...) |
Open a new issue |
get_file_content(project, file_path, ref) |
Fetch a file from the repository |
get_repository_tree(project, ...) |
List files/directories in the repository |
search_code(project, query) |
Search project code |
get_pipeline_status(project, ref) |
Pipeline status for a branch |
get_failed_pipeline_logs(project, pipeline_id) |
Logs for failed jobs in a pipeline |
list_project_labels(project) |
List labels available on the project |
The project argument accepts either a numeric ID or a group/project
path. Path lookups are cached in Redis for one hour when REDIS_URL
is configured (resolve_project_id in codeward/mcp_server/server.py).
Registered in codeward/mcp_server/resources.py:
| URI | Returns |
|---|---|
gitlab://project/{path}/readme |
The project's README.md |
gitlab://project/{path}/ci-config |
The project's .gitlab-ci.yml |
gitlab://project/{path}/merge-requests/open |
Open merge requests |
gitlab://project/{path}/issues/open |
Open issues |
gitlab://project/{path}/pipelines/latest |
Latest pipeline status |
Registered in codeward/mcp_server/prompts.py:
| Prompt | Arguments |
|---|---|
review_merge_request |
project, mr_iid |
explain_pipeline_failure |
project, pipeline_id |
summarize_issue |
project, issue_iid |
Add an entry to your Claude Desktop config (e.g.
~/Library/Application Support/Claude/claude_desktop_config.json on
macOS, or %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"codeward": {
"transport": "http",
"url": "http://localhost:8420/mcp",
"headers": {
"Authorization": "Bearer replace-with-a-long-random-string"
}
}
}
}Drop the headers block if CODEWARD_MCP_KEY is unset. Restart
Claude Desktop and you should see the Codeward tools, resources, and
prompts in the MCP picker.
Any client that speaks streamable-HTTP MCP can talk to Codeward. Point
it at http://<host>:8420/mcp and (if applicable) add a
Authorization: Bearer <CODEWARD_MCP_KEY> header.
# With auth
curl -i \
-H "Accept: text/event-stream" \
-H "Authorization: Bearer $CODEWARD_MCP_KEY" \
http://localhost:8420/mcp
# Without auth (CODEWARD_MCP_KEY unset)
curl -i \
-H "Accept: text/event-stream" \
http://localhost:8420/mcpA 401 Unauthorized JSON response indicates the bearer token did not
match. A successful response is an SSE stream — kill it with Ctrl-C.
Codeward agents can be granted tools from any external MCP server
without writing Python. The connection is opened lazily on first use,
cached, health-checked between calls, and merged into the agent's
toolset alongside GitLabToolkit. The implementation lives in
codeward/mcp_client/{registry,manager}.py.
codeward:
mcp_servers:
context7:
url: https://mcp.context7.com/mcp
transport: streamable-http # streamable-http | sse
auth_type: bearer # bearer | header | none
auth_token_env: CONTEXT7_TOKEN # env var that holds the token
enabled: true
description: Context7 documentation lookups
sentry:
url: https://mcp.sentry.dev/mcp
transport: streamable-http
auth_type: header
headers:
Authorization: Bearer ${SENTRY_TOKEN} # ${VAR} expansion is supportedThe schema is defined by MCPServerConfig in
codeward/mcp_client/registry.py:
| Field | Type | Notes |
|---|---|---|
url |
string | The MCP endpoint. ${ENV_VAR} references are expanded from the process environment. |
transport |
string | streamable-http (default) or sse. |
auth_type |
string | bearer, header, or none. |
auth_token_env |
string | For auth_type: bearer — the env var holding the token. The header Authorization: Bearer <token> is added automatically. |
headers |
mapping | For auth_type: header — literal headers to send. ${ENV_VAR} is expanded. |
enabled |
bool | Disable a server without removing the entry. Defaults to true. |
description |
string | Free-form, surfaced in logs. |
Reference the server name from the agent YAML's mcp_servers: list:
# agents/chat.yml
name: chat
type: chat
# ...
mcp_servers:
- context7
- sentryAt run time, MCPConnectionManager.get_tools_for_agent (in
codeward/mcp_client/manager.py) collects the configured MCPTools
instances and Agno merges them into the agent's toolset alongside
GitLabToolkit.
A project can replace the MCP server list per agent in its
.codeward.yml:
codeward:
mcp_servers:
chat: # agent name
- context7 # only context7 in this repo, drop sentryIf mcp_servers is set for an agent in a project's .codeward.yml,
that list completely replaces the agent-level list — it is not
merged with it.
- Lazy connect. Connections are opened on first use and cached for the lifetime of the process.
- Health checks. Before reusing a cached connection, the manager
calls
is_alive()and reconnects if the connection has gone stale. - Failure isolation. If an MCP server is unreachable, the connection attempt is logged and the agent runs without that server's tools — it does not abort the run.
- Tool prefixing. Tool names are prefixed with the server name
(
tool_name_prefix=config.name) to avoid collisions across multiple MCP servers.
The manager exposes a health_check() helper used by the
/health endpoint to report per-server connectivity. Failing servers
will show up there with false so you can spot misconfigured tokens
quickly.
- AGENTS.md — agent architecture, YAML schema, and the MCP-related sections cross-referenced from here
- Configuration — env var reference and the
codeward.mcp_serverssection - Multi-Agent Flows — flows can also call agents that have external MCP tools attached