Mcpunk

Latest version: v0.12.0

Safety actively analyzes 723144 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 2 of 3

0.7.0

basically, works with mirascope now

For example below, this is VERY scrappy just a PoC

python
import asyncio
import logging
from collections.abc import Sequence
from pathlib import Path
from typing import Any, cast

import dotenv
from mirascope import BaseMessageParam, BaseTool, ToolCallPart, ToolResultPart
from mirascope.core import anthropic
from mirascope.core.anthropic import AnthropicCallResponse
from mirascope.mcp.client import ( type: ignore[attr-defined]
StdioServerParameters,
create_mcp_client,
)

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


if (__dotenv_file := Path(__file__).parent.parent / ".env").exists():
dotenv.load_dotenv(__dotenv_file)


mcp_server_params = StdioServerParameters(
command="/Users/michael/.local/bin/uvx",
args=["mcpunk"],
args=["--from", "/Users/michael/git/mcpunk", "--no-cache", "mcpunk"],
env=None,
)


async def llm_call_with_mcp_tool_loop(
system_prompt: str,
initial_query: str,
repo: Path,
max_iter: int = 100,
) -> str:
async with create_mcp_client(mcp_server_params) as mcp_client:
_tools = await mcp_client.list_tools()
tools: Sequence[type[BaseTool]] = cast(Sequence[type[BaseTool]], _tools)
print("tools", tools)

anthropic.call( type: ignore[misc,call-overload]
"claude-3-5-sonnet-latest",
tools=tools,
)
def do_llm_call(ctxt_: list[BaseMessageParam]) -> list[BaseMessageParam]:
return ctxt_

ctxt: list[BaseMessageParam] = [
BaseMessageParam(role="system", content=system_prompt),
BaseMessageParam(role="user", content=initial_query + f"\nproject: {repo!s}"),
]
for _i in range(max_iter):
resp: AnthropicCallResponse = cast(AnthropicCallResponse, do_llm_call(ctxt_=ctxt))
print(f"LLM Response {resp.message_param}")

Now put the LLMs response back into the context. Like a chat! The LLM
needs to know what it previously responded with.
for resp_block in resp.response.content:
if resp_block.type == "text":
ctxt.append(BaseMessageParam(role="assistant", content=resp_block.text))
elif resp_block.type == "tool_use":
ctxt.append(
BaseMessageParam(
role="assistant",
content=[
ToolCallPart(
type="tool_call",
name=resp_block.name,
args=cast(dict[str, Any], resp_block.input),
id=resp_block.id,
)
],
)
)

If the machine requested tool uses, then use em and slap them back
in the context.
if resp.tools:
for tool in resp.tools:
try:
call_result = await tool.call()
call_result_str = str(call_result)
print(f"Tool response {call_result_str}")
ctxt.append(
BaseMessageParam(
role="user",
content=[
ToolResultPart(
type="tool_result",
name=tool.tool_call.name,
content=str(call_result_str),
id=tool.tool_call.id,
is_error=False,
)
],
)
)
except Exception as e:
Mirascope's MCP client tends to provide very poor errors here.
logger.exception("There was an error calling the tool")
ctxt.append(
BaseMessageParam(
role="user",
content=[
ToolResultPart(
type="tool_result",
name=tool.tool_call.name,
content=str(e),
id=tool.tool_call.id,
is_error=True,
)
],
)
)
else:
If no tools then we assume this is the final response message.
final_response = resp.content
print(final_response)
return final_response
print("Too many iterations!")
return "Too many iterations!"


def main() -> None:
asyncio.run(
llm_call_with_mcp_tool_loop(
"You are a code reviewer who is methodical and thorough. "
"You MUST use ALL available tools extensively to analyze code. "
"Your approach should be systematic: configure project, list files, "
"check diffs, then examine each change in detail using multiple tool calls. "
"A proper review requires at least 10-15 tool calls - anything less is insufficient. "
"Explore: changed files, their dependencies, imports, and affected functionality.",
...
"Please configure the specified project and review "
"the diff with the main branch. Use AT LEAST 10 tool calls to explore "
"the codebase properly. Start with configuration, then file listing, then "
"diffs, then detailed examination of each change. Your final response should be "
"a comprehensive PR review after thorough tool-based exploration.",
Path("~/git/mcpunk").expanduser().absolute(),
)
)


if __name__ == "__main__":
main()



What's Changed
* Allow filter to be plain string by jurasofish in https://github.com/jurasofish/mcpunk/pull/41
* Simpler `proj_file` input by jurasofish in https://github.com/jurasofish/mcpunk/pull/42


**Full Changelog**: https://github.com/jurasofish/mcpunk/compare/v0.6.1...v0.7.0

0.6.1

What's Changed
* Homepage link in readme by jurasofish in https://github.com/jurasofish/mcpunk/pull/37


**Full Changelog**: https://github.com/jurasofish/mcpunk/compare/v0.6.0...v0.6.1

0.6.0

What's Changed

Big change is that responses are generally now plain text, and use fewer chars than before. And this also makes them easier to read if you're looking at the tool responses in e.g. claude desktop or in the log file (`~/.mcpunk/mcpunk.log` by default)

* Output test durations by jurasofish in https://github.com/jurasofish/mcpunk/pull/31
* Makefile `install-dev` -> `install` (and now frozen) by jurasofish in https://github.com/jurasofish/mcpunk/pull/32
* Use `inspect.cleandoc` over `textwrap.dedent` for tool resp by jurasofish in https://github.com/jurasofish/mcpunk/pull/33
* Tweak `MCPToolOutput` by jurasofish in https://github.com/jurasofish/mcpunk/pull/34
* Return text from tools by jurasofish in https://github.com/jurasofish/mcpunk/pull/35
* Rework file tree by jurasofish in https://github.com/jurasofish/mcpunk/pull/36


**Full Changelog**: https://github.com/jurasofish/mcpunk/compare/v0.5.1...v0.6.0

0.5.1

What's Changed
* Move pre-commit to dev dependency by jurasofish in https://github.com/jurasofish/mcpunk/pull/30


**Full Changelog**: https://github.com/jurasofish/mcpunk/compare/v0.5.0...v0.5.1

0.5.0

With this release
- The log file should be a bit more useful, as it's INFO level by default. Less spammy
- Faster loading of python files thanks to AST caching
- Minor tweaks to Python and Markdown chunkers plus basic automated testing for them

What's Changed
* `log_inputs` -> `log_inputs_outputs` with default INFO log level by jurasofish in https://github.com/jurasofish/mcpunk/pull/23
* Default INFO log level by jurasofish in https://github.com/jurasofish/mcpunk/pull/24
* Cache AST by jurasofish in https://github.com/jurasofish/mcpunk/pull/25
* Settings frozen with better path handling by jurasofish in https://github.com/jurasofish/mcpunk/pull/26
* Skip empty python chunks by jurasofish in https://github.com/jurasofish/mcpunk/pull/27
* MardownChunker handle content before first header by jurasofish in https://github.com/jurasofish/mcpunk/pull/28
* Test WholeFileChunker by jurasofish in https://github.com/jurasofish/mcpunk/pull/29


**Full Changelog**: https://github.com/jurasofish/mcpunk/compare/v0.4.3...v0.5.0

0.4.3

What's Changed
* Update dependencies and tweak version pinning by jurasofish in https://github.com/jurasofish/mcpunk/pull/22


**Full Changelog**: https://github.com/jurasofish/mcpunk/compare/v0.4.2...v0.4.3

Page 2 of 3

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.