Javier Tarí 39 Posted Tuesday at 04:39 PM After many times of copying and pasting debug messages (OutputDebugString) from the debugger view to the Claude Code (CC) form, so it could read it all, I decided making a MCP server that will just provide that: services to catch and read debug messages I had no idea on how to do that, but nevertheless asked Claude (rhe chat) to make a plan for it, so CC could just follow the instruction. Then asked CC to add it to one test MCP server I already had working. With help from another CC instance that connected to the server and tried using it, and finding why it errores, it's working now I've attached the initial document that Claude made (could have asked it to GPT or Gemini or whatever) Then I asked the CC instance that was using it for helpful enhancements I've attached both documents If there is interest on it, I could make a public repo MCP-debug-server.md MCP-debug-server-enhancements.md 1 1 Share this post Link to post
pyscripter 837 Posted Tuesday at 04:48 PM 8 minutes ago, Javier Tarí said: If there is interest on it, I could make a public repo Please. Share this post Link to post
Lars Fosdal 1928 Posted yesterday at 06:28 AM In my experience, in a multithreaded app, Windows' built in OutputDebugString will from time to time fail to actually output your data, causing gaps in the logging. I ended up sending all my debug output through my own logger, which queue the output in a pre-allocated circular buffer and batch writes periodically to file and to actual debug out (if I turn that option on). Share this post Link to post
Kas Ob. 158 Posted yesterday at 07:57 AM I did made small package that capture all the output from the IDE at real time compiling/building, it does capture all messages in Output tab and Build tab, but it was tested on few and old IDEs, it works on XE8, Seattle( can't remember which number it was as i don't use it) , Delphi 2010, 2007 and 2009 . If that is needed and can help you then i need a confirm before revisiting it, also it will need your help to make sure it will work on newer IDEs, so do you need it ? Share this post Link to post
Javier Tarí 39 Posted yesterday at 12:11 PM 19 hours ago, pyscripter said: Please. Here it is; I used the GTK repo for the MCP server itself. You and anyone can use my code in any way without need to give me anything; not a link, not nothing. JavierusTk/MCPServer 1 Share this post Link to post
Javier Tarí 39 Posted yesterday at 12:18 PM 5 hours ago, Lars Fosdal said: In my experience, in a multithreaded app, Windows' built in OutputDebugString will from time to time fail to actually output your data, causing gaps in the logging. I ended up sending all my debug output through my own logger, which queue the output in a pre-allocated circular buffer and batch writes periodically to file and to actual debug out (if I turn that option on). Sure, but here I'm not using OutputDebugString as a log, but as a real time information tool: the difference is the usage with the AI; the AI can read it while the program is running, not at a later time. I will add some easy to implement additional features that will allow the agent to do a much better and faster debugging Share this post Link to post
Javier Tarí 39 Posted yesterday at 12:21 PM 4 hours ago, Kas Ob. said: If that is needed and can help you then i need a confirm before revisiting it, also it will need your help to make sure it will work on newer IDEs, so do you need it ? I'm not sure if I will use it, but would be glad to have it and check/adapt to D12/13 Right now the AI agent compiles with the CLI compiler, so it gets back all the compiler messages; but I'm considering interaction with the IDE, which would mean compiling from it 1 Share this post Link to post
Lars Fosdal 1928 Posted yesterday at 01:54 PM 1 hour ago, Javier Tarí said: Sure, but here I'm not using OutputDebugString as a log, but as a real time information tool: the difference is the usage with the AI; the AI can read it while the program is running, not at a later time. I will add some easy to implement additional features that will allow the agent to do a much better and faster debugging I understand that. My point was that OutputDebugString can fail on the windows side, so that the content does not always reach the listeners. YMMV. 1 Share this post Link to post
Kas Ob. 158 Posted 12 hours ago Here is a simple console app that extract exports from a DLL, this is needed to confirm compatibility or if adjustment is needed to make the Compiler/IDE message hook working on newer IDEs than mine. 20 hours ago, Javier Tarí said: but would be glad to have it and check/adapt to D12/13 If the function is still there with the same signature (declaration) or similar then it will work, also if it is the same then that means it will work for all IDE newer than XE8. Please, run the following console app, and dump the coreideXXX.bpl exports, and either pack the compress the whole output and attach it here, or just if there is the following or similar procedures @Msglines@TCompilerMsgLine@ @Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox53System@%DelphiInterface$26Msglinesintf@IMessageGroup% @Msglines@TCompilerMsgLine@Draw$qqrp20Vcl@Graphics@TCanvasrx18System@Types@TRecto @Msglines@TCompilerMsgLine@GetLineText$qqrv They are together, and might different after "@Msglines@TCompilerMsgLine@" but that what i need to decode and solve in case there is difference, the above are form coreide220.bpl (XE8) the original code of dumping/getting exports from DLL is by David Heffernan https://stackoverflow.com/questions/31917322/how-to-get-all-the-exported-functions-in-a-dll program DllExportDumper; {$APPTYPE CONSOLE} uses SysUtils, Classes, Windows; // original code by David Heffernan from SO, modified to run in 64bit and support 64bit DLLs // https://stackoverflow.com/questions/31917322/how-to-get-all-the-exported-functions-in-a-dll function ImageNtHeader(Base: Pointer): Pointer; stdcall; external 'dbghelp.dll'; function ImageRvaToVa(NtHeaders: Pointer; Base: Pointer; Rva: ULONG; LastRvaSection: Pointer): Pointer; stdcall; external 'dbghelp.dll'; function EnumerateImageExportedFunctionNames(const ImageName: string; NamesList: TStrings): Boolean; const IMAGE_FILE_MACHINE_AMD64 = $8664; type PIMAGE_NT_HEADERSEX = ^IMAGE_NT_HEADERSEX; IMAGE_NT_HEADERSEX = record Signature: DWORD; FileHeader: IMAGE_FILE_HEADER; {$IFNDEF FPC}{$IF CompilerVersion >= 24.0 } {$LEGACYIFEND ON} {$IFEND}{$ENDIF} {$IF not Declared(IMAGE_OPTIONAL_HEADER64)} OptionalHeader: IMAGE_OPTIONAL_HEADER; {$ELSE} OptionalHeader: IMAGE_OPTIONAL_HEADER32; {$IFEND} end; var i: Integer; FileHandle: THandle; ImageHandle: THandle; ImagePointer: Pointer; NtHeader: Pointer; HeaderEx: PIMAGE_NT_HEADERSEX; // trick to slide by 16 instead of defining record for both 32bit and 64bit, support many compilers ExportTable: ^_IMAGE_EXPORT_DIRECTORY; NamesPtr: PULONG; NamePtr: PAnsiChar; Is64Bit: Boolean; begin Result := False; NamesList.Clear; FileHandle := CreateFile(PChar(ImageName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if FileHandle = INVALID_HANDLE_VALUE then Exit; try ImageHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); if ImageHandle = 0 then Exit; try ImagePointer := MapViewOfFile(ImageHandle, FILE_MAP_READ, 0, 0, 0); if not Assigned(ImagePointer) then Exit; try NtHeader := ImageNtHeader(ImagePointer); if not Assigned(NtHeader) or (PIMAGE_NT_HEADERSEX(NtHeader)^.Signature <> $00004550) then Exit; Is64Bit := PIMAGE_NT_HEADERSEX(NtHeader)^.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; if Is64Bit then // slide by 16 byte for 64bit HeaderEx := PIMAGE_NT_HEADERSEX(NativeUInt(NtHeader) + 16) else HeaderEx := PIMAGE_NT_HEADERSEX(NtHeader); ExportTable := ImageRvaToVa(NtHeader, ImagePointer, HeaderEx^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, nil); if not Assigned(ExportTable) or (ExportTable^.NumberOfNames = 0) or (ExportTable^.NumberOfNames > 1000000) or (Cardinal(ExportTable^.AddressOfNames) = 0) then Exit; NamesPtr := ImageRvaToVa(NtHeader, ImagePointer, Cardinal(ExportTable^.AddressOfNames), nil); if not Assigned(NamesPtr) then Exit; for i := 0 to ExportTable^.NumberOfNames - 1 do begin if NamesPtr^ = 0 then Exit; NamePtr := ImageRvaToVa(NtHeader, ImagePointer, NamesPtr^, nil); if not Assigned(NamePtr) then Exit; NamesList.Add(string(NamePtr)); inc(NamesPtr); end; Result := True; finally UnmapViewOfFile(ImagePointer); end; finally CloseHandle(ImageHandle); end; finally CloseHandle(FileHandle); end; end; procedure DumpDllExports(const FileName, OutputPath: string); var ExportsList: TStringList; OutputFileName: string; begin ExportsList := TStringList.Create; try if EnumerateImageExportedFunctionNames(FileName, ExportsList) then begin Writeln('Exports API found: ', ExportsList.Count); Writeln('Saving exports for ', FileName); OutputFileName := IncludeTrailingPathDelimiter(OutputPath) + ExtractFileName(FileName) + '.txt'; ExportsList.SaveToFile(OutputFileName); Writeln('File saved -> ', OutputFileName); end else Writeln('No exports found or parsing failed for ', FileName); finally ExportsList.Free; end; end; begin try DumpDllExports('D:\Program Files (x86)\Embarcadero\Studio\16.0\bin\coreide220.bpl', GetCurrentDir); DumpDllExports('C:\Windows\System32\d3dx10_33.dll', GetCurrentDir); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. For this exact two dlls on my device the coreide220.bpl return more than 22k exports, while that direct3d library return only 177. 1 Share this post Link to post
Lajos Juhász 332 Posted 11 hours ago This is from Delphi 12 @Msglines@TCompilerMsgLine@ @Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox53System@%DelphiInterface$26Msglinesintf@IMessageGroup% @Msglines@TCompilerMsgLine@Draw$qqrp20Vcl@Graphics@TCanvasrx18System@Types@TRecto @Msglines@TCompilerMsgLine@GetLineText$qqrv 1 1 Share this post Link to post